ALLOW_SNAPSHOT_ISOLATION e READ_COMMITTED_SNAPSHOT

38

A maioria dos fóruns e exemplos online sempre sugere ter os dois ALLOW_SNAPSHOT_ISOLATIONe READ_COMMITTED_SNAPSHOTativá-los sempre que alguém fizer uma captura instantânea, versão de linha ou pergunta semelhante.

Eu acho que a palavra INSTANTÂNEO nas duas configurações fica um pouco confusa. Eu pensei que, para que o mecanismo de banco de dados usasse o controle de versão de linha em vez de bloqueios para o comportamento padrão READ_COMMITTED, o banco de dados READ_COMMITTED_SNAPSHOTestá definido como ON, independentemente da ALLOW_SNAPSHOT_ISOLATIONconfiguração.

A ALLOW_SNAPSHOT_ISOLATIONconfiguração é configurada como ON apenas para permitir o isolamento de instantâneo ao iniciar uma transação (por exemplo, INSTANTÂNEO DE CONFIGURAÇÃO DO NÍVEL DE ISOLAÇÃO DA TRANSAÇÃO), independentemente da READ_COMMITTED_SNAPSHOTconfiguração.

O único motivo para ter essas duas configurações definidas como ON é quando ele precisa ter o controle de versão de linha READ COMMITTED E o isolamento de captura instantânea.

Minha pergunta é: meu entendimento está incorreto de alguma forma? E que essas duas configurações sempre devem estar ativadas juntas (especialmente para versão de linha READ COMMITTED)?

Travis
fonte

Respostas:

25

Sua compreensão está correta. Fica um pouco confuso.

Kim Tripp (um dos programadores do SQL Server e parte integrante do SQLSkills) analisa exatamente o que você declarou nos vídeos do MCM sobre Snapshot Isolation . Avance rapidamente para 41:45 no vídeo para chegar à parte em que ela responde à sua pergunta.

Se você usar, ALLOW_SNAPSHOT_ISOLATIONcertifique-se de usar SET TRANSACTION ISOLATION LEVEL SNAPSHOTseu código, caso contrário, você não obterá nenhum dos benefícios.

Se você definir SET READ_COMMITTED_SNAPSHOT ON, não será necessário modificar nenhum código. O MS SQL Server aplica automaticamente o isolamento de instantâneo a essa tabela.

Não testei para ver o que acontece se você solicitar um nível de isolamento diferente no seu código. Suspeito que ele substitua essa opção, mas teste primeiro.

Uma rápida olhada na sobrecarga de desempenho usando o Snapshot Isolation.

Bom artigo sobre como o isolamento de instantâneo pode alterar o comportamento esperado do seu aplicativo . Ele mostra exemplos de como uma instrução de atualização e uma instrução de seleção podem retornar resultados totalmente diferentes e inesperados.

Ali Razeghi
fonte
Obrigado pelo link. Como outros BOL, ela discutiu essas duas configurações de forma independente e coletiva (é aí que fica um pouco confuso, ou talvez eu pense demais). Eu tive que testá-lo para entender melhor.
Travis
4
Esta é uma ótima resposta e gostaria apenas de esclarecer alguns itens. Primeiro, se você estiver apenas digitalizando o vídeo, comece às 23:18 e 41:45. O início acrescenta mais detalhes. Embora Kim mencione uma resposta para a pergunta original, ainda é necessário modificar o código se estiver usando as duas. Read_Committed_Snapshot é um isolamento no nível da instrução, em outras palavras, aplica-se apenas à instrução em execução no momento. Allow_Snapshot_Isolation é um isolamento no nível da transação, tudo entre o Begin Tran e o Commit. Eles podem ser acoplados separadamente, mas a mesma sobrecarga de 14 bytes por linha é estabelecida.
Delux
obrigado por adicionar os detalhes adicionais sobre a sobrecarga de 14 bytes que está sendo estabelecida. Kim analisa isso no vídeo, mas é muito útil tê-lo aqui também em texto.
Ali Razeghi 26/11
15

OK, voltei para casa e testei. Aqui está a observação.

CREATE DATABASE TEST;
GO
CREATE TABLE TABLE1
(
    ID tinyint,
    Details varchar(10)
);
GO
INSERT INTO TABLE1
VALUES (1, 'Original');
GO

SELECT
    name,
    snapshot_isolation_state_desc,
    is_read_committed_snapshot_on
FROM sys.databases
WHERE name = 'TEST';
GO

Primeiro teste com as duas configurações confirmadas como OFF.

Consulta 1

USE TEST;

BEGIN TRAN
UPDATE TABLE1
SET Details = 'Update'
WHERE ID = 1;

--COMMIT;
--ROLLBACK;
GO

Consulta 2

USE TEST;

SELECT ID, Details
FROM TABLE1
WHERE ID = 1;
GO

Nesse teste, a consulta 2 está aguardando a confirmação da consulta 1, dm_tran_locks DMV mostra esse bloqueio exclusivo na TABLE1 incorrido pela consulta 1.

USE TEST;

SELECT
    DB_NAME(tl.resource_database_id) AS DBName,
    resource_type,
    OBJECT_NAME(resource_associated_entity_id) AS tbl_name,
    request_mode,
    request_status,
    request_session_id
FROM sys.dm_tran_locks tl
WHERE 
    resource_database_id = db_id('TEST')
    AND resource_type = 'OBJECT'

Segundo teste , reversão da transação anterior, defina READ_COMMITTED_SNAPSHOT ON, mas deixe ALLOW_SNAPSHOT_ISOLATION OFF.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT ON
WITH ROLLBACK IMMEDIATE;
GO

Execute a Consulta 1 e execute a consulta 2. O DMV mostra a consulta 1 com bloqueio exclusivo, mas a consulta 2 retorna detalhes com 'Original' sem a consulta 1 confirmar a transação. Parece que o controle de versão da linha READ_COMMITTED está em vigor.

Adicionar SET TRANSACTION ISOLATION LEVEL SNAPSHOT;a consulta 1 e a consulta 2 e executar a consulta 1 ou a consulta 2 retorna erro - A transação de isolamento de captura instantânea falhou ao acessar o banco de dados 'TEST' porque o isolamento de captura instantânea não é permitido nesse banco de dados. Use ALTER DATABASE para permitir o isolamento de instantâneo.

Terceiro teste , reversão da transação anterior. Ative READ_COMMITTED_SNAPSHOT e ALLOW_SNAPSHOT_ISOLATION.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT OFF
WITH ROLLBACK IMMEDIATE;
GO

ALTER DATABASE TEST
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

Execute a consulta 1 e, em seguida, a consulta 2. O DMV mostra o bloqueio exclusivo incorrido pela consulta 1. A consulta 2 parece estar aguardando a conclusão da consulta 1. Ativar ALLOW_SNAPSHOT_ISOLATION ON não parece ativar o controle de versão READ COMMITTED.

Adicionando SET TRANSACTION ISOLATION LEVEL SNAPSHOT;à consulta 1 e à consulta 2. Execute a consulta 1 e, em seguida, a consulta 2. Enquanto o DMV mostra a consulta 1 com bloqueio exclusivo, a consulta 2 retorna os detalhes com 'Original'. O isolamento de instantâneo parece estar no lugar.

A observação do teste mostra que READ_COMMITTED_SNAPSHOTela própria ativa / desativa o controle de versão da linha READ COMMITTED independentemente da ALLOW_SNAPSHOT_ISOLATIONconfiguração e vice-versa.

Travis
fonte
4

Sua compreensão está correta. Eu gosto da definição curta, limpa e simples daqui :

Quando a opção de banco de dados READ_COMMITTED_SNAPSHOT está LIGADA, as transações que configuram o nível de isolamento confirmado pela leitura usam o controle de versão da linha.

Quando a opção do banco de dados ALLOW_SNAPSHOT_ISOLATION está LIGADA, as transações podem definir o nível de isolamento da captura instantânea.

Parece que muitos mal-entendidos vêm do próprio MS. Por exemplo, aqui eles dizem:

Se você definir a opção de banco de dados READ_COMMITTED_SNAPSHOT como ON, o mecanismo de banco de dados utilizará o controle de versão de linha e de captura instantânea como padrão, em vez de usar bloqueios para proteger os dados.

Mas o "isolamento de captura instantânea" mencionado não é igual ao comportamento da transação ao qual set transaction isolation level snapshoté aplicado.

Quanto à diferença, uma boa explicação está aqui .

Provavelmente seria melhor se READ_COMMITTED_SNAPSHOT fosse nomeado como READ_COMMITTED_ROW_VERSIONING ou algo assim. :)

ov
fonte
0

Eu gosto deste resumo da Microsoft :

Definir a opção READ_COMMITTED_SNAPSHOT ON permite o acesso a linhas com versão sob o nível de isolamento READ COMMITTED padrão. Se a opção READ_COMMITTED_SNAPSHOT estiver configurada como OFF, você deverá definir explicitamente o nível de isolamento de Captura Instantânea para cada sessão para acessar as linhas com versão.

flam3
fonte