Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Há condições de erro que ocorrem com transações que acessam tabelas com otimização de memória.
-
- A transação atual tentou atualizar um registro que foi atualizado desde que a transação foi iniciada.
-
- A transação atual não foi confirmada devido a uma falha de validação de leitura repetível.
-
- A transação atual não foi confirmada devido a uma falha de validação serializável.
-
- Uma transação anterior da qual a transação atual dependia foi anulada, e a transação atual não pode mais ser concluída.
Uma causa comum desses erros é a interferência entre a execução simultânea da transação. A ação corretiva comum é repetir a transação.
Para obter mais informações sobre essas condições de erro, consulte a seção sobre detecção de conflitos, validação e confirmação de verificações de dependência em transações em tabelas de Memory-Optimized.
Deadlocks (código de erro 1205) não podem ocorrer para tabelas com otimização de memória. Os bloqueios não são usados para tabelas com otimização de memória. No entanto, se o aplicativo já tiver lógica de tentativas para deadlocks, a lógica existente poderá ser estendida para incluir os novos códigos de erro.
Considerações sobre a repetição
Normalmente, os aplicativos encontrarão conflitos entre transações e precisarão implementar a lógica de repetição para resolver esses conflitos. O número de conflitos encontrados depende de vários fatores:
Contenção para linhas individuais. O potencial de conflitos aumenta à medida que o número de transações que tentam atualizar a mesma linha aumenta.
Número de linhas que foram lidas por transações REPEATABLE READ. Quanto mais linhas forem lidas, maior a chance de que algumas dessas linhas sejam atualizadas por transações simultâneas. Isso causa falhas de validação de leitura repetíveis.
Tamanho dos intervalos de verificação usados por transações SERIALIZABLE. Quanto maior o intervalo de varredura, maior a chance de que transações simultâneas introduzam linhas fantasmas, causando falhas na validação serializável.
É difícil para um aplicativo evitar esses conflitos, exigindo lógica de repetição.
Importante
As transações de leitura e gravação que acessam tabelas com otimização de memória exigem lógica de repetição.
Considerações sobre transações de Read-Only e procedimentos armazenados compilados nativamente
Transações somente leitura que abrangem uma única execução de um procedimento armazenado compilado nativamente não exigem validação para transações REPEATABLE READ e SERIALIZABLE. Conflitos de gravação não podem ocorrer devido a uma transação estar em modo somente leitura.
No entanto, falhas de dependência ainda podem ocorrer. Falhas de dependência são mais raras do que erros resultantes de conflitos. Portanto, em muitos casos, a lógica de repetição específica não é necessária para transações somente leitura que abrangem execuções únicas de procedimentos armazenados compilados nativamente.
Considerações sobre transações Read-Only e transações entre contêineres
Transações somente leitura entre contêineres, que são iniciadas fora do contexto de um procedimento armazenado nativo, não realizam validação se as tabelas otimizadas para memória forem todas acessadas sob isolamento SNAPSHOT. No entanto, quando as tabelas com otimização de memória são acessadas sob os níveis de isolamento REPEATABLE READ ou SERIALIZABLE, a validação é executada no momento da confirmação. Nesse caso, a lógica de repetição pode ser necessária.
Para obter mais informações, consulte a seção sobre transações entre contêineres em níveis de isolamento de transação.
Implementando a lógica de nova tentativa
Assim como acontece com todas as transações que acessam tabelas com otimização de memória, você precisa considerar a lógica de repetição para lidar com possíveis falhas, como conflitos de gravação (código de erro 41302) ou falhas de dependência (código de erro 41301). Na maioria dos aplicativos, a taxa de falha será baixa, mas ainda é necessário lidar com falhas repetindo a transação. Duas maneiras sugeridas de implementar a lógica de repetição são:
Novas tentativas do lado do cliente. As novas tentativas do lado do cliente são a maneira preferencial de implementar a lógica de repetição no caso geral. O aplicativo cliente captura o erro gerado pela transação e tenta novamente a transação. Se um aplicativo cliente existente tiver lógica de repetição para lidar com deadlocks, você poderá estender o aplicativo para lidar com os novos códigos de erro.
Usando um procedimento armazenado de wrapper. O cliente chama um procedimento armazenado Transact-SQL interpretado que invoca o procedimento armazenado compilado de forma nativa ou executa a transação. Em seguida, o procedimento wrapper usa a lógica try/catch para capturar o erro e, se necessário, tentar novamente a chamada do procedimento. É possível que os resultados sejam retornados ao cliente antes da falha e o cliente não saiba descartá-los. Portanto, para ser seguro, é melhor usar esse método somente com procedimentos armazenados compilados nativamente que não retornam conjuntos de resultados para o cliente.
A lógica de repetição pode ser implementada no Transact-SQL ou no código do aplicativo na camada intermediária.
Dois possíveis motivos para considerar a lógica de repetição são:
O aplicativo cliente tem lógica de repetição para outros códigos de erro, como 1205, que você pode estender.
Conflitos são raros e é importante reduzir a latência de ponta a ponta usando a execução preparada. Para obter mais informações sobre como executar procedimentos armazenados compilados nativamente diretamente, consulte Procedimentos armazenados compilados nativamente.
O exemplo a seguir mostra a lógica de tentativa em um procedimento armazenado Transact-SQL interpretado que contém uma chamada para um procedimento armazenado compilado de forma nativa ou para uma transação entre diferentes contêineres.
CREATE PROCEDURE usp_my_procedure @param1 type1, @param2 type2, ...
AS
BEGIN
-- number of retries - tune based on the workload
DECLARE @retry INT = 10
WHILE (@retry > 0)
BEGIN
BEGIN TRY
-- exec usp_my_native_proc @param1, @param2, ...
-- or
-- BEGIN TRANSACTION
-- ...
-- COMMIT TRANSACTION
SET @retry = 0
END TRY
BEGIN CATCH
SET @retry -= 1
-- the error number for deadlocks (1205) does not need to be included for
-- transactions that do not access disk-based tables
IF (@retry > 0 AND error_number() in (41302, 41305, 41325, 41301, 1205))
BEGIN
-- these error conditions are transaction dooming - rollback the transaction
-- this is not needed if the transaction spans a single native proc execution
-- as the native proc will simply rollback when an error is thrown
IF XACT_STATE() = -1
ROLLBACK TRANSACTION
-- use a delay if there is a high rate of write conflicts (41302)
-- length of delay should depend on the typical duration of conflicting transactions
-- WAITFOR DELAY '00:00:00.001'
END
ELSE
BEGIN
-- insert custom error handling for other error conditions here
-- throw if this is not a qualifying error condition
;THROW
END
END CATCH
END
END
Consulte Também
Noções básicas sobre transações em tabelas de Memory-Optimized
Transações em tabelas de Memory-Optimized
Diretrizes para níveis de isolamento de transação com tabelas de Memory-Optimized