ALLOW_SNAPSHOT_ISOLATION und READ_COMMITTED_SNAPSHOT

38

In den meisten Online-Foren und -Beispielen wird immer empfohlen, beide zu verwenden ALLOW_SNAPSHOT_ISOLATIONund diese READ_COMMITTED_SNAPSHOTOption auf ON zu setzen, wenn jemand eine Frage zu Snapshot, Zeilenversionsverwaltung oder einer ähnlichen Frage stellt.

Ich denke, das Wort SNAPSHOT in beiden Einstellungen wird etwas verwirrend. Ich dachte, damit das Datenbankmodul die Zeilenversionierung anstelle von Sperren für das Standardverhalten von READ_COMMITTED verwendet, wird die Datenbank unabhängig von der Einstellung READ_COMMITTED_SNAPSHOTauf ON gesetzt .ALLOW_SNAPSHOT_ISOLATION

Die ALLOW_SNAPSHOT_ISOLATIONEinstellung ist nur auf ON gesetzt, um die Snapshot-Isolation beim Starten einer Transaktion zu ermöglichen (z. B. SET TRANSACTION ISOLATION LEVEL SNAPSHOT), unabhängig von der READ_COMMITTED_SNAPSHOTEinstellung.

Der einzige Grund, diese beiden Einstellungen auf ON zu setzen, besteht darin, dass READ COMMITTED-Zeilenversionierung UND Snapshot-Isolation erforderlich sind .

Meine Frage ist, ist mein Verständnis in irgendeiner Weise falsch? Und dass diese beiden Einstellungen immer zusammen auf ON gesetzt werden müssen (insbesondere für die READ COMMITTED-Zeilenversionierung)?

Travis
quelle

Antworten:

25

Dein Verständnis ist korrekt. Es wird ein bisschen verwirrend.

Kim Tripp (einer der Programmierer von SQL Server und ein integraler Bestandteil von SQLSkills) geht genau das durch, was Sie in den MCM-Videos zu Snapshot Isolation angegeben haben . Schnell um 41:45 im Video, um zu dem Teil zu gelangen, in dem sie Ihre Frage beantwortet.

Wenn Sie verwenden, ALLOW_SNAPSHOT_ISOLATIONstellen Sie sicher, dass Sie SET TRANSACTION ISOLATION LEVEL SNAPSHOTin Ihrem Code verwenden, sonst erhalten Sie keinen der Vorteile.

Wenn Sie festlegen SET READ_COMMITTED_SNAPSHOT ON, müssen Sie keinen Code ändern. MS SQL Server wendet automatisch die Snapshot-Isolation für diese Tabelle an.

Ich habe nicht getestet, was passiert, wenn Sie nach einer anderen Isolationsstufe in Ihrem Code fragen. Ich vermute, dass diese Option dadurch überschrieben wird, aber testen Sie sie zuerst.

Ein kurzer Überblick über den Leistungsaufwand mithilfe der Snapshot-Isolierung.

Guter Artikel darüber, wie die Snapshot-Isolierung das erwartete Verhalten Ihrer App ändern kann . Es werden Beispiele dafür gezeigt, wie eine Update-Anweisung und eine Select-Anweisung völlig unterschiedliche und unerwartete Ergebnisse liefern können.

Ali Razeghi
quelle
Danke für den Link. Wie andere BOL hat sie diese beiden Einstellungen unabhängig und gemeinsam besprochen (da wird es etwas verwirrend, oder ich überlege es mir). Ich musste es ausprobieren, um ein besseres Verständnis zu bekommen.
Travis
4
Dies ist eine großartige Antwort und ich möchte nur einige Punkte klarstellen. Wenn Sie nur das Video scannen, beginnen Sie um 23:18 Uhr und um 41:45 Uhr. Die frühe Zeit fügt mehr Details hinzu. Obwohl Kim eine Antwort auf die ursprüngliche Frage erwähnt, muss der Code noch geändert werden, wenn beide verwendet werden. Read_Committed_Snapshot ist eine Isolation auf Anweisungsebene, gilt also nur für die derzeit ausgeführte Anweisung. Allow_Snapshot_Isolation ist eine Isolation auf Transaktionsebene, alles zwischen Begin Tran und Commit. Sie können separat belegt werden, es wird jedoch derselbe 14-Byte-Overhead pro Zeile eingerichtet.
Delux
Vielen Dank, dass Sie die zusätzlichen Details zum 14-Byte-Overhead hinzugefügt haben. Kim geht es im Video durch, aber es ist sehr nützlich, es hier auch als Text zu haben.
Ali Razeghi
15

OK, ging nach Hause und getestet. Hier ist die Beobachtung.

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

Erster Test mit beiden Einstellungen als AUS bestätigt.

Abfrage 1

USE TEST;

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

--COMMIT;
--ROLLBACK;
GO

Abfrage 2

USE TEST;

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

In diesem Test wartet Abfrage 2 darauf, dass Abfrage 1 festgeschrieben wird. Dm_tran_locks DMV zeigt diese exklusive Sperre für TABLE1 an, die von Abfrage 1 verursacht wurde.

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'

Zweiter Test , vorherige Transaktion zurücksetzen, READ_COMMITTED_SNAPSHOT auf ON setzen, ALLOW_SNAPSHOT_ISOLATION jedoch auf OFF lassen.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT ON
WITH ROLLBACK IMMEDIATE;
GO

Führen Sie Abfrage 1 und Abfrage 2 aus. DMV zeigt, dass Abfrage 1 eine exklusive Sperre aufweist, Abfrage 2 jedoch Details mit "Original" zurückgibt, ohne dass Abfrage 1 die Transaktion festschreibt. Es scheint, dass die READ_COMMITTED-Zeilenversionierung vorhanden ist.

Wenn Sie SET TRANSACTION ISOLATION LEVEL SNAPSHOT;Abfrage 1 und Abfrage 2 hinzufügen und Abfrage 1 oder Abfrage 2 ausführen, wird ein Fehler zurückgegeben. Die Snapshot-Isolationstransaktion konnte nicht auf die Datenbank 'TEST' zugreifen, da die Snapshot-Isolation in dieser Datenbank nicht zulässig ist. Verwenden Sie ALTER DATABASE, um die Snapshot-Isolierung zu ermöglichen.

Dritter Test , Rollback der vorherigen Transaktion. Setzen Sie READ_COMMITTED_SNAPSHOT OFF und ALLOW_SNAPSHOT_ISOLATION ON.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT OFF
WITH ROLLBACK IMMEDIATE;
GO

ALTER DATABASE TEST
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

Führen Sie Abfrage 1 und dann Abfrage 2 aus. DMV zeigt die von Abfrage 1 verursachte exklusive Sperre an. Abfrage 2 wartet anscheinend auf den Abschluss von Abfrage 1. Durch Aktivieren von ALLOW_SNAPSHOT_ISOLATION wird die READ COMMITTED-Zeilenversionierung nicht aktiviert.

Hinzufügen SET TRANSACTION ISOLATION LEVEL SNAPSHOT;zu Abfrage 1 und Abfrage 2. Führen Sie Abfrage 1 und dann Abfrage 2 aus. Während in DMV für Abfrage 1 eine exklusive Sperre angezeigt wird, gibt Abfrage 2 Details mit "Original" zurück. Die Snapshot-Isolierung scheint vorhanden zu sein.

Die Beobachtung des Tests zeigt, dass READ_COMMITTED_SNAPSHOTdie READ COMMITTED-Zeilenversionierung unabhängig von der ALLOW_SNAPSHOT_ISOLATIONEinstellung aktiviert / deaktiviert wird und umgekehrt.

Travis
quelle
4

Dein Verständnis ist korrekt. Ich mag die kurze, klare und einfache Definition von hier :

Wenn die Datenbankoption READ_COMMITTED_SNAPSHOT auf ON gesetzt ist, verwenden Transaktionen, die die Lesezusage-Isolationsstufe festlegen, die Zeilenversionierung.

Wenn die Datenbankoption ALLOW_SNAPSHOT_ISOLATION auf ON gesetzt ist, können Transaktionen die Snapshot-Isolationsstufe festlegen.

Es scheint, dass viele Missverständnisse von MS selbst herrühren. Zum Beispiel sagen sie hier :

Wenn Sie die Datenbankoption READ_COMMITTED_SNAPSHOT auf ON setzen, verwendet das Datenbankmodul standardmäßig die Zeilenversionierung und die Snapshot-Isolierung , anstatt Sperren zum Schutz der Daten zu verwenden.

Die erwähnte "Snapshot-Isolation" ist jedoch nicht gleichbedeutend mit dem Verhalten der Transaktion, für die sie set transaction isolation level snapshotangewendet wird.

Wie für den Unterschied ist schön Erklärung hier .

Wahrscheinlich wäre es besser, wenn READ_COMMITTED_SNAPSHOT als READ_COMMITTED_ROW_VERSIONING oder so ähnlich bezeichnet würde. :)

ov
quelle
0

Ich mag diese Zusammenfassung von Microsoft :

Durch Festlegen der Option READ_COMMITTED_SNAPSHOT ON wird der Zugriff auf versionierte Zeilen unter der Standardisolationsstufe READ COMMITTED ermöglicht. Wenn die Option READ_COMMITTED_SNAPSHOT auf OFF gesetzt ist, müssen Sie die Snapshot-Isolationsstufe für jede Sitzung explizit festlegen, um auf versionierte Zeilen zugreifen zu können.

flam3
quelle