Disseram-me que se sua transação consistir em múltiplas instruções, então o SNAPSHOT
nível de isolamento da transação é a única maneira de garantir visualizações de dados consistentes em um determinado momento. Por que o nível de isolamento da transação é SERIALIZABLE
inadequado para esta tarefa? Por design, as travas que SERIALIZABLE
prendem são muito apertadas.
Acho que a lacuna no meu entendimento é que não tenho certeza de quando SERIALIZABLE
isso acontece. Um script como o abaixo provavelmente será muito útil para encontrar o que estou perdendo.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT TOP (1) * FROM [Hit_Me_First];
WAITFOR DELAY '00:02:00';
SELECT TOP (1) * FROM [Hit_Me_Second];
COMMIT;
As pessoas sempre parecem querer compreender os níveis de isolamento em termos de bloqueios.
Isto é um tanto estranho porque os níveis de isolamento geralmente não são definidos por bloqueio, mas sim por fenômenos de simultaneidade * que podem ocorrer em cada nível.
Alguns produtos implementam alguns níveis de isolamento usando bloqueio, mas isso não é verdade para todos os níveis ou produtos. Por exemplo, o SQL Server tem implementações baseadas em bloqueio e em controle de versão para o nível de isolamento confirmado de leitura .
Até mesmo o isolamento serializável é implementado no SQL Server sem bloqueio quando você usa o mecanismo de armazenamento OLTP (Hekaton) na memória. A propósito, o PostgreSQL também implementa serializável usando um esquema de versionamento.
O isolamento de instantâneo garante que você veja apenas os dados confirmados como estavam no início da transação. O início da transação ocorre na primeira vez que você acessa os dados versionados dentro da transação, e não quando você emite
BEGIN TRAN
.Serializable também fornece uma visão consistente dos dados como eram em um determinado momento, mas esse momento geralmente não é o início da transação. Para entender isso, considere a definição do SQL Standard (ênfase adicionada):
Se os efeitos forem os mesmos como se todas as transações fossem executadas em série, em alguma ordem, claramente você verá apenas os dados confirmados como eram quando sua transação foi executada em série (ou seja, sem atividade simultânea). A diferença crucial é que você não pode saber exatamente qual era o cronograma de execuções em série.
Se você realmente precisa pensar sobre isso durante a implementação do bloqueio, considere que o SQL Server utiliza bloqueios suficientes para garantir que todos os dados necessários à sua transação não sejam alterados após serem lidos. Além disso, nenhum dado novo que seria visto pela sua transação se ela fosse executada novamente poderá ser adicionado até que a transação termine (sem 'fantasmas').
Através dessa lente, a visão do momento é desde quando o último bloqueio necessário para sua transação foi adquirido até o final da transação. Por conveniência, você pode escolher que isso signifique a hora em que a transação terminou.
Mais uma vez, enfatizo que isso é consequência de uma decisão de implementação. Poderia mudar, em princípio. Eu encorajaria você a entender a concorrência através das garantias lógicas fornecidas e dos efeitos da concorrência evitados.
Para obter mais informações, consulte meu artigo O nível de isolamento serializável e o restante da série para outros níveis de isolamento, incluindo isolamento de instantâneo .
* Qualquer efeito devido à simultaneidade que não ocorreria se a transação fosse executada sozinha
A questão aqui é a definição de “ponto no tempo”.
No SQL Server,
SERIALIZABLE
garante que você verá dados consistentes como eram em algum momento durante a vida da transação.Este não será necessariamente o momento em que a transação começou, pois no seu exemplo os bloqueios poderiam ser colocados em
Hit_Me_First
, masHit_Me_Second
podem continuar variando durante o tempo intermediário de espera.A consistência é garantida pelo fato de que
Hit_Me_First
não pode variar após a consulta; portanto, por mais queHit_Me_Second
varie apósHit_Me_First
o bloqueio, você obterá um instantâneo consistente de ambas as tabelas no momento em queHit_Me_Second
for finalmente consultada.(O impasse e o cancelamento da transação, é claro, também são um resultado possível desse algoritmo em geral - portanto, você tem a garantia de obter resultados consistentes ou nenhum resultado ).
Agora,
SNAPSHOT
o isolamento funciona de maneira diferente, pois todos os dados são lidos como estavam no momento em que a transação começou (e não em algum outro momento durante a vida da transação), e não pode haver impasse entre transações que leem apenas dados.A desvantagem
SNAPSHOT
é que ele não garante uma execução serializável verdadeira para transações que são gravadas.Vale a pena mencionar de passagem que no Oracle
SERIALIZABLE
é sinônimo deSNAPSHOT
, devido ao que muitos consideram desleixo na definição do padrão ANSI, e o Oracle não possui um modo de isolamento verdadeiramente serializável.A definição de senso comum de serializável é que " o efeito de duas transações programadas para execução simultânea é garantido como o mesmo que se fossem executadas em algum agendamento totalmente serial ", mas não é assim que o padrão ANSI o define.
O termo que se refere ao modo de isolamento que usa instantâneos e também está de acordo com a definição de senso comum de serializável, é chamado de "isolamento de instantâneo serializável" (SSI), e entre os principais mecanismos de banco de dados só estou ciente de que o Postgres possui esse modo.