Otimizar transações no SQL Data Warehouse do AzureOptimizing transactions in Azure SQL Data Warehouse

Saiba como otimizar o desempenho do código transacional no SQL Data Warehouse do Azure, minimizando o risco de reversões longas.Learn how to optimize the performance of your transactional code in Azure SQL Data Warehouse while minimizing risk for long rollbacks.

Transações e registro em logTransactions and logging

As transações são um componente importante de um mecanismo de banco de dados relacional.Transactions are an important component of a relational database engine. O SQL Data Warehouse usa transações durante a modificação de dados.SQL Data Warehouse uses transactions during data modification. Essas transações podem ser implícitas ou explícitas.These transactions can be explicit or implicit. Instruções INSERT, UPDATE e DELETE únicas são exemplos de transações implícitas.Single INSERT, UPDATE, and DELETE statements are all examples of implicit transactions. Transações explícitas usam BEGIN TRAN, COMMIT TRAN ou ROLLBACK TRAN.Explicit transactions use BEGIN TRAN, COMMIT TRAN, or ROLLBACK TRAN. Transações explícitas são normalmente utilizadas quando várias instruções de modificação precisam ser agrupadas em uma única unidade atômica.Explicit transactions are typically used when multiple modification statements need to be tied together in a single atomic unit.

O SQL Data Warehouse do Azure confirma as alterações no banco de dados usando os logs de transação.Azure SQL Data Warehouse commits changes to the database using transaction logs. Cada distribuição tem seu próprio log de transações.Each distribution has its own transaction log. As gravações de log de transações são automáticas.Transaction log writes are automatic. Não é necessária nenhuma configuração.There is no configuration required. No entanto, apesar desse processo garantir a gravação, ele introduz uma sobrecarga no sistema.However, whilst this process guarantees the write it does introduce an overhead in the system. Você pode minimizar esse impacto ao escrever um código transacionalmente eficiente.You can minimize this impact by writing transactionally efficient code. De modo geral, um código transacionalmente eficiente se enquadra em duas categorias.Transactionally efficient code broadly falls into two categories.

  • Use constructos de registro em log mínimos sempre que possívelUse minimal logging constructs whenever possible
  • Processar dados usando lotes com escopo para evitar transações de longa execução singularesProcess data using scoped batches to avoid singular long running transactions
  • Adotar um padrão de alternância de partições para grandes modificações de uma determinada partiçãoAdopt a partition switching pattern for large modifications to a given partition

Registro mínimo em log vs. registro total em logMinimal vs. full logging

Ao contrário de operações totalmente registradas em log, que usam o log de transações para acompanhar cada linha alterada, as operações minimamente registradas em log controlam apenas as alocações de extensão e as alterações de metadados.Unlike fully logged operations, which use the transaction log to keep track of every row change, minimally logged operations keep track of extent allocations and meta-data changes only. Portanto, o registro em log mínimo envolve o registro em log apenas das informações necessárias para reverter a transação após uma falha ou para uma solicitação explícita (ROLLBACK TRAN).Therefore, minimal logging involves logging only the information that is required to roll back the transaction after a failure, or for an explicit request (ROLLBACK TRAN). Como muito menos informações são rastreadas no log de transações, uma operação minimamente registrada em log tem um desempenho melhor do que uma operação totalmente registrada em log de tamanho similar.As much less information is tracked in the transaction log, a minimally logged operation performs better than a similarly sized fully logged operation. Além disso, como ocorrem menos gravações no log de transações, uma quantidade menor de dados de log será gerada e, portanto, é mais eficiente em relação à E/S.Furthermore, because fewer writes go the transaction log, a much smaller amount of log data is generated and so is more I/O efficient.

Os limites de segurança de transação só se aplicam às operações totalmente registradas em log.The transaction safety limits only apply to fully logged operations.

Observação

As operações minimamente registradas em log podem participar de transações explícitas.Minimally logged operations can participate in explicit transactions. Como todas as alterações nas estruturas de alocação são rastreadas, é possível reverter operações minimamente registradas em log.As all changes in allocation structures are tracked, it is possible to roll back minimally logged operations.

Operações minimamente registradas em logMinimally logged operations

As seguintes operações podem ser minimamente registradas em log:The following operations are capable of being minimally logged:

  • CREATE TABLE AS SELECT (CTAS)CREATE TABLE AS SELECT (CTAS)
  • INSERT..SELECTINSERT..SELECT
  • CREATE INDEXCREATE INDEX
  • ALTER INDEX REBUILDALTER INDEX REBUILD
  • DROP INDEXDROP INDEX
  • TRUNCATE TABLETRUNCATE TABLE
  • DROP TABLEDROP TABLE
  • ALTER TABLE SWITCH PARTITIONALTER TABLE SWITCH PARTITION

Observação

As operações de movimentação de dados internos (como BROADCAST e SHUFFLE) não são afetados pelo limite de segurança da transação.Internal data movement operations (such as BROADCAST and SHUFFLE) are not affected by the transaction safety limit.

Registro mínimo em log com carregamento em massaMinimal logging with bulk load

CTAS e INSERT...SELECT são ambas operações de carregamento em massa.CTAS and INSERT...SELECT are both bulk load operations. No entanto, ambas são influenciadas pela definição da tabela de destino e dependem do cenário de carga.However, both are influenced by the target table definition and depend on the load scenario. A tabela a seguir explica quando as operações em massa são total ou minimamente registradas:The following table explains when bulk operations are fully or minimally logged:

Índice principalPrimary Index Cenário de cargaLoad Scenario Modo de registro em logLogging Mode
HeapHeap QualquerAny MínimoMinimal
Índice clusterizadoClustered Index Tabela de destino vaziaEmpty target table MínimoMinimal
Índice clusterizadoClustered Index As linhas carregadas não se sobrepõem às páginas existentes no destinoLoaded rows do not overlap with existing pages in target MínimoMinimal
Índice clusterizadoClustered Index Linhas carregadas se sobrepõem com páginas existentes no destinoLoaded rows overlap with existing pages in target CompletoFull
Índice columnstore clusterizadoClustered Columnstore Index Tamanho do lote >= 102.400 por distribuição alinhada por partiçãoBatch size >= 102,400 per partition aligned distribution MínimoMinimal
Índice columnstore clusterizadoClustered Columnstore Index Tamanho do lote < 102.400 por distribuição alinhada por partiçãoBatch size < 102,400 per partition aligned distribution CompletoFull

Vale a pena observar que todas as gravações para atualizar índices secundários ou não clusterizados sempre serão operações com log completo.It is worth noting that any writes to update secondary or non-clustered indexes will always be fully logged operations.

Importante

O SQL Data Warehouse possui 60 distribuições.SQL Data Warehouse has 60 distributions. Portanto, supondo que todas as linhas são distribuídas uniformemente e em uma única partição, o seu lote deverá conter 6.144.000 linhas ou mais para ser minimamente registrado ao gravar em um Índice Columnstore Clusterizado.Therefore, assuming all rows are evenly distributed and landing in a single partition, your batch will need to contain 6,144,000 rows or larger to be minimally logged when writing to a Clustered Columnstore Index. Se a tabela estiver particionada e as linhas que estiverem sendo inseridas se estenderem pelos limites de partição, você precisará de 6.144.000 linhas por limite de partição, considerando uma distribuição uniforme de dados.If the table is partitioned and the rows being inserted span partition boundaries, then you will need 6,144,000 rows per partition boundary assuming even data distribution. Cada partição em cada distribuição deve exceder independentemente o limite de 102.400 linhas para a inserção ser minimamente registrada em log para a distribuição.Each partition in each distribution must independently exceed the 102,400 row threshold for the insert to be minimally logged into the distribution.

Carregar dados em uma tabela não vazia com um índice clusterizado pode, muitas vezes, conter uma combinação de linhas total e minimamente registradas em log.Loading data into a non-empty table with a clustered index can often contain a mixture of fully logged and minimally logged rows. Um índice clusterizado é uma árvore balanceada (árvore b) das páginas.A clustered index is a balanced tree (b-tree) of pages. Se a página que estiver sendo gravada já contiver linhas de outra transação, então essas gravações serão totalmente registradas em log.If the page being written to already contains rows from another transaction, then these writes will be fully logged. No entanto, se a página estiver vazia, a gravação para essa página será minimamente registrada em log.However, if the page is empty then the write to that page will be minimally logged.

Otimizando exclusõesOptimizing deletes

DELETE é uma operação totalmente registrada em log.DELETE is a fully logged operation. Se você precisar excluir uma grande quantidade de dados de uma tabela ou uma partição, geralmente fará mais sentido SELECT (selecionar) os dados que deseja manter, que podem ser executados como uma operação minimamente registrada em log.If you need to delete a large amount of data in a table or a partition, it often makes more sense to SELECT the data you wish to keep, which can be run as a minimally logged operation. Para selecionar os dados, crie uma nova tabela com CTAS.To select the data, create a new table with CTAS. Uma vez criado, use RENAME para trocar a tabela antiga pela tabela criada recentemente.Once created, use RENAME to swap out your old table with the newly created table.

-- Delete all sales transactions for Promotions except PromotionKey 2.

--Step 01. Create a new table select only the records we want to kep (PromotionKey 2)
CREATE TABLE [dbo].[FactInternetSales_d]
WITH
(    CLUSTERED COLUMNSTORE INDEX
,    DISTRIBUTION = HASH([ProductKey])
,     PARTITION     (    [OrderDateKey] RANGE RIGHT 
                                    FOR VALUES    (    20000101, 20010101, 20020101, 20030101, 20040101, 20050101
                                                ,    20060101, 20070101, 20080101, 20090101, 20100101, 20110101
                                                ,    20120101, 20130101, 20140101, 20150101, 20160101, 20170101
                                                ,    20180101, 20190101, 20200101, 20210101, 20220101, 20230101
                                                ,    20240101, 20250101, 20260101, 20270101, 20280101, 20290101
                                                )
)
AS
SELECT     *
FROM     [dbo].[FactInternetSales]
WHERE    [PromotionKey] = 2
OPTION (LABEL = 'CTAS : Delete')
;

--Step 02. Rename the Tables to replace the 
RENAME OBJECT [dbo].[FactInternetSales]   TO [FactInternetSales_old];
RENAME OBJECT [dbo].[FactInternetSales_d] TO [FactInternetSales];

Otimizando atualizaçõesOptimizing updates

UPDATE é uma operação totalmente registrada em log.UPDATE is a fully logged operation. Se você precisar atualizar um grande número de linhas em uma tabela ou em uma partição, no geral, poderá ser muito mais proveitoso usar uma operação minimamente registrada em log, tal como CTAS.If you need to update a large number of rows in a table or a partition, it can often be far more efficient to use a minimally logged operation such as CTAS to do so.

No exemplo abaixo, uma atualização completa de tabela foi convertida em um CTAS para que o registro em log mínimo seja possível.In the example below a full table update has been converted to a CTAS so that minimal logging is possible.

Nesse caso, adiciona-se retrospectivamente um valor de desconto às vendas na tabela:In this case, we are retrospectively adding a discount amount to the sales in the table:

--Step 01. Create a new table containing the "Update". 
CREATE TABLE [dbo].[FactInternetSales_u]
WITH
(    CLUSTERED INDEX
,    DISTRIBUTION = HASH([ProductKey])
,     PARTITION     (    [OrderDateKey] RANGE RIGHT 
                                    FOR VALUES    (    20000101, 20010101, 20020101, 20030101, 20040101, 20050101
                                                ,    20060101, 20070101, 20080101, 20090101, 20100101, 20110101
                                                ,    20120101, 20130101, 20140101, 20150101, 20160101, 20170101
                                                ,    20180101, 20190101, 20200101, 20210101, 20220101, 20230101
                                                ,    20240101, 20250101, 20260101, 20270101, 20280101, 20290101
                                                )
                )
)
AS 
SELECT
    [ProductKey]  
,    [OrderDateKey] 
,    [DueDateKey]  
,    [ShipDateKey] 
,    [CustomerKey] 
,    [PromotionKey] 
,    [CurrencyKey] 
,    [SalesTerritoryKey]
,    [SalesOrderNumber]
,    [SalesOrderLineNumber]
,    [RevisionNumber]
,    [OrderQuantity]
,    [UnitPrice]
,    [ExtendedAmount]
,    [UnitPriceDiscountPct]
,    ISNULL(CAST(5 as float),0) AS [DiscountAmount]
,    [ProductStandardCost]
,    [TotalProductCost]
,    ISNULL(CAST(CASE WHEN [SalesAmount] <=5 THEN 0
         ELSE [SalesAmount] - 5
         END AS MONEY),0) AS [SalesAmount]
,    [TaxAmt]
,    [Freight]
,    [CarrierTrackingNumber] 
,    [CustomerPONumber]
FROM    [dbo].[FactInternetSales]
OPTION (LABEL = 'CTAS : Update')
;

--Step 02. Rename the tables
RENAME OBJECT [dbo].[FactInternetSales]   TO [FactInternetSales_old];
RENAME OBJECT [dbo].[FactInternetSales_u] TO [FactInternetSales];

--Step 03. Drop the old table
DROP TABLE [dbo].[FactInternetSales_old]

Observação

A recriação de tabelas grandes pode se beneficiar do uso de recursos de gerenciamento de carga de trabalho do SQL Data Warehouse.Re-creating large tables can benefit from using SQL Data Warehouse workload management features. Para obter mais informações, consulte Classes de recurso para gerenciamento de carga de trabalho.For more information, see Resource classes for workload management.

Otimizando com alternância de partiçãoOptimizing with partition switching

Se forem observadas modificações em larga escala dentro de uma partição de tabela, então, é recomendável um padrão de comutação de partição.If faced with large-scale modifications inside a table partition, then a partition switching pattern makes sense. Se a modificação de dados for significativa e alcançar várias partições, a iteração nas partições obterá o mesmo resultado.If the data modification is significant and spans multiple partitions, then iterating over the partitions achieves the same result.

As etapas para executar uma alternância de partições são as seguintes:The steps to perform a partition switch are as follows:

  1. Criar uma partição de saída vaziaCreate an empty out partition
  2. Executar a “atualização” como um CTASPerform the 'update' as a CTAS
  3. Alternar os dados existentes na tabela de saídaSwitch out the existing data to the out table
  4. Inserir os novos dadosSwitch in the new data
  5. Limpar os dadosClean up the data

No entanto, para ajudar a identificar as partições para comutar, crie o procedimento auxiliar a seguir.However, to help identify the partitions to switch, create the following helper procedure.

CREATE PROCEDURE dbo.partition_data_get
    @schema_name           NVARCHAR(128)
,    @table_name               NVARCHAR(128)
,    @boundary_value           INT
AS
IF OBJECT_ID('tempdb..#ptn_data') IS NOT NULL
BEGIN
    DROP TABLE #ptn_data
END
CREATE TABLE #ptn_data
WITH    (    DISTRIBUTION = ROUND_ROBIN
        ,    HEAP
        )
AS
WITH CTE
AS
(
SELECT     s.name                            AS [schema_name]
,        t.name                            AS [table_name]
,         p.partition_number                AS [ptn_nmbr]
,        p.[rows]                        AS [ptn_rows]
,        CAST(r.[value] AS INT)            AS [boundary_value]
FROM        sys.schemas                    AS s
JOIN        sys.tables                    AS t    ON  s.[schema_id]        = t.[schema_id]
JOIN        sys.indexes                    AS i    ON     t.[object_id]        = i.[object_id]
JOIN        sys.partitions                AS p    ON     i.[object_id]        = p.[object_id] 
                                                AND i.[index_id]        = p.[index_id] 
JOIN        sys.partition_schemes        AS h    ON     i.[data_space_id]    = h.[data_space_id]
JOIN        sys.partition_functions        AS f    ON     h.[function_id]        = f.[function_id]
LEFT JOIN    sys.partition_range_values    AS r     ON     f.[function_id]        = r.[function_id] 
                                                AND r.[boundary_id]        = p.[partition_number]
WHERE i.[index_id] <= 1
)
SELECT    *
FROM    CTE
WHERE    [schema_name]        = @schema_name
AND        [table_name]        = @table_name
AND        [boundary_value]    = @boundary_value
OPTION (LABEL = 'dbo.partition_data_get : CTAS : #ptn_data')
;
GO

Esse procedimento maximiza a reutilização de código e deixa o exemplo de comutação de partições mais compacto.This procedure maximizes code reuse and keeps the partition switching example more compact.

O código a seguir demonstra as etapas mencionadas anteriormente para obter uma rotina de comutação de partição completa.The following code demonstrates the steps mentioned previously to achieve a full partition switching routine.

--Create a partitioned aligned empty table to switch out the data 
IF OBJECT_ID('[dbo].[FactInternetSales_out]') IS NOT NULL
BEGIN
    DROP TABLE [dbo].[FactInternetSales_out]
END

CREATE TABLE [dbo].[FactInternetSales_out]
WITH
(    DISTRIBUTION = HASH([ProductKey])
,    CLUSTERED COLUMNSTORE INDEX
,     PARTITION     (    [OrderDateKey] RANGE RIGHT 
                                    FOR VALUES    (    20020101, 20030101
                                                )
                )
)
AS
SELECT *
FROM    [dbo].[FactInternetSales]
WHERE 1=2
OPTION (LABEL = 'CTAS : Partition Switch IN : UPDATE')
;

--Create a partitioned aligned table and update the data in the select portion of the CTAS
IF OBJECT_ID('[dbo].[FactInternetSales_in]') IS NOT NULL
BEGIN
    DROP TABLE [dbo].[FactInternetSales_in]
END

CREATE TABLE [dbo].[FactInternetSales_in]
WITH
(    DISTRIBUTION = HASH([ProductKey])
,    CLUSTERED COLUMNSTORE INDEX
,     PARTITION     (    [OrderDateKey] RANGE RIGHT 
                                    FOR VALUES    (    20020101, 20030101
                                                )
                )
)
AS 
SELECT
    [ProductKey]  
,    [OrderDateKey] 
,    [DueDateKey]  
,    [ShipDateKey] 
,    [CustomerKey] 
,    [PromotionKey] 
,    [CurrencyKey] 
,    [SalesTerritoryKey]
,    [SalesOrderNumber]
,    [SalesOrderLineNumber]
,    [RevisionNumber]
,    [OrderQuantity]
,    [UnitPrice]
,    [ExtendedAmount]
,    [UnitPriceDiscountPct]
,    ISNULL(CAST(5 as float),0) AS [DiscountAmount]
,    [ProductStandardCost]
,    [TotalProductCost]
,    ISNULL(CAST(CASE WHEN [SalesAmount] <=5 THEN 0
         ELSE [SalesAmount] - 5
         END AS MONEY),0) AS [SalesAmount]
,    [TaxAmt]
,    [Freight]
,    [CarrierTrackingNumber] 
,    [CustomerPONumber]
FROM    [dbo].[FactInternetSales]
WHERE    OrderDateKey BETWEEN 20020101 AND 20021231
OPTION (LABEL = 'CTAS : Partition Switch IN : UPDATE')
;

--Use the helper procedure to identify the partitions
--The source table
EXEC dbo.partition_data_get 'dbo','FactInternetSales',20030101
DECLARE @ptn_nmbr_src INT = (SELECT ptn_nmbr FROM #ptn_data)
SELECT @ptn_nmbr_src

--The "in" table
EXEC dbo.partition_data_get 'dbo','FactInternetSales_in',20030101
DECLARE @ptn_nmbr_in INT = (SELECT ptn_nmbr FROM #ptn_data)
SELECT @ptn_nmbr_in

--The "out" table
EXEC dbo.partition_data_get 'dbo','FactInternetSales_out',20030101
DECLARE @ptn_nmbr_out INT = (SELECT ptn_nmbr FROM #ptn_data)
SELECT @ptn_nmbr_out

--Switch the partitions over
DECLARE @SQL NVARCHAR(4000) = '
ALTER TABLE [dbo].[FactInternetSales]    SWITCH PARTITION '+CAST(@ptn_nmbr_src AS VARCHAR(20))    +' TO [dbo].[FactInternetSales_out] PARTITION '    +CAST(@ptn_nmbr_out AS VARCHAR(20))+';
ALTER TABLE [dbo].[FactInternetSales_in] SWITCH PARTITION '+CAST(@ptn_nmbr_in AS VARCHAR(20))    +' TO [dbo].[FactInternetSales] PARTITION '        +CAST(@ptn_nmbr_src AS VARCHAR(20))+';'
EXEC sp_executesql @SQL

--Perform the clean-up
TRUNCATE TABLE dbo.FactInternetSales_out;
TRUNCATE TABLE dbo.FactInternetSales_in;

DROP TABLE dbo.FactInternetSales_out
DROP TABLE dbo.FactInternetSales_in
DROP TABLE #ptn_data

Minimizar o registro em log com pequenos lotesMinimize logging with small batches

Para grandes operações de modificação de dados, talvez faça sentido dividir a operação em partes ou em lotes para abranger a unidade de trabalho.For large data modification operations, it may make sense to divide the operation into chunks or batches to scope the unit of work.

Um código a seguir é um exemplo de trabalho.A following code is a working example. O tamanho do lote foi definido como um número trivial para realçar a técnica.The batch size has been set to a trivial number to highlight the technique. Na realidade, o tamanho do lote seria significativamente maior.In reality, the batch size would be significantly larger.

SET NO_COUNT ON;
IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
    DROP TABLE #t;
    PRINT '#t dropped';
END

CREATE TABLE #t
WITH    (    DISTRIBUTION = ROUND_ROBIN
        ,    HEAP
        )
AS
SELECT    ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS seq_nmbr
,        SalesOrderNumber
,        SalesOrderLineNumber
FROM    dbo.FactInternetSales
WHERE    [OrderDateKey] BETWEEN 20010101 and 20011231
;

DECLARE    @seq_start        INT = 1
,        @batch_iterator    INT = 1
,        @batch_size        INT = 50
,        @max_seq_nmbr    INT = (SELECT MAX(seq_nmbr) FROM dbo.#t)
;

DECLARE    @batch_count    INT = (SELECT CEILING((@max_seq_nmbr*1.0)/@batch_size))
,        @seq_end        INT = @batch_size
;

SELECT COUNT(*)
FROM    dbo.FactInternetSales f

PRINT 'MAX_seq_nmbr '+CAST(@max_seq_nmbr AS VARCHAR(20))
PRINT 'MAX_Batch_count '+CAST(@batch_count AS VARCHAR(20))

WHILE    @batch_iterator <= @batch_count
BEGIN
    DELETE
    FROM    dbo.FactInternetSales
    WHERE EXISTS
    (
            SELECT    1
            FROM    #t t
            WHERE    seq_nmbr BETWEEN  @seq_start AND @seq_end
            AND        FactInternetSales.SalesOrderNumber        = t.SalesOrderNumber
            AND        FactInternetSales.SalesOrderLineNumber    = t.SalesOrderLineNumber
    )
    ;

    SET @seq_start = @seq_end
    SET @seq_end = (@seq_start+@batch_size);
    SET @batch_iterator +=1;
END

Diretrizes de pausa e dimensionamentoPause and scaling guidance

O SQL Data Warehouse do Azure permite pausar, resumir e dimensionar seu data warehouse sob demanda.Azure SQL Data Warehouse lets you pause, resume, and scale your data warehouse on demand. Quando você pausa ou dimensiona o SQL Data Warehouse, deve reconhecer que todas as transações em trânsito serão encerradas imediatamente, fazendo com que qualquer transação aberta seja revertida.When you pause or scale your SQL Data Warehouse, it is important to understand that any in-flight transactions are terminated immediately; causing any open transactions to be rolled back. Se sua carga de trabalho tiver emitido uma modificação de dados de longa duração e incompleta antes de a operação de dimensionamento ou pausa, o trabalho precisará ser desfeito.If your workload had issued a long running and incomplete data modification prior to the pause or scale operation, then this work will need to be undone. Esse desfazer pode impactar no tempo necessário para pausar ou dimensionar o banco de dados do SQL Data Warehouse do Azure.This undoing might impact the time it takes to pause or scale your Azure SQL Data Warehouse database.

Importante

As operações UPDATE e DELETE são totalmente registradas em log e, portanto, essas operações de desfazer/refazer podem demorar significativamente mais do que as operações equivalentes minimamente registradas em log.Both UPDATE and DELETE are fully logged operations and so these undo/redo operations can take significantly longer than equivalent minimally logged operations.

O melhor cenário é permitir que as transações de modificação de dados em trânsito sejam concluídas antes da pausa ou do dimensionamento do SQL Data Warehouse.The best scenario is to let in flight data modification transactions complete prior to pausing or scaling SQL Data Warehouse. No entanto, esse cenário nem sempre pode ser prático.However, this scenario might not always be practical. Para reduzir o risco de uma longa reversão, considere uma das seguintes opções:To mitigate the risk of a long rollback, consider one of the following options:

  • Regenere operações de execução longa usando CTASRewrite long running operations using CTAS
  • Interromper a operação em partes; operando em um subconjunto das linhasBreak the operation into chunks; operating on a subset of the rows

Próximas etapasNext steps

Consulte Transações no SQL Data Warehouse para saber mais sobre os níveis de isolamento e os limites transacionais.See Transactions in SQL Data Warehouse to learn more about isolation levels and transactional limits. Para obter uma visão geral de outras práticas recomendadas, confira Práticas recomendadas para o Azure SQL Data Warehouse.For an overview of other Best Practices, see SQL Data Warehouse Best Practices.