Grundlegendes zu zeilenversionsbasierten Isolationsstufen

Die Zeilenversionsverwaltung stellt in SQL Server ein allgemeines Framework zur Unterstützung folgender Features dar:

  • Erstellen der inserted- und deleted-Tabellen in Triggern. Für alle durch den Trigger geänderten Zeilen wird die Versionsverwaltung verwendet. Das schließt die Zeilen ein, die durch die Anweisung geändert wurden, mit der der Start des Triggers erfolgte, sowie alle vom Trigger bewirkten Datenänderungen.

  • Unterstützen von Multiple Active Result Sets (MARS). Wenn eine MARS-Sitzung eine Datenänderungsanweisung (z. B. INSERT, UPDATE oder DELETE) ausgibt, während es ein aktives Resultset gibt, wird für die von der Änderungsanweisung betroffenen Zeilen die Versionsverwaltung verwendet.

  • Unterstützen von Indexvorgängen, die die ONLINE-Option angeben.

  • Unterstützen von zeilenversionsbasierten Transaktionsisolationsstufen:

    • Eine neue Implementierung der Read Committed-Isolationsstufe, die die Zeilenversionsverwaltung verwendet, um die Lesekonsistenz auf Anweisungsebene zu gewährleisten.

    • Eine neue Isolationsstufe – Snapshot, um die Lesekonsistenz auf der Transaktionsebene zu gewährleisten.

Die tempdb-Datenbank muss über ausreichend Speicherplatz verfügen, um die Versionen speichern zu können. Wenn tempdb voll ist, brechen Aktualisierungsvorgänge die Versionsverwaltung ab und können fortgesetzt werden, wogegen Lesevorgänge einen Fehler erzeugen können, weil eine bestimmte Zeilenversion, die benötigt wird, nicht mehr vorhanden ist. Das wirkt sich auf Vorgänge wie Trigger, MARS und Onlineindizierung aus. Weitere Informationen finden Sie unter Ressourcenverwendung bei der Zeilenversionsverwaltung.

Das Verwenden der Zeilenversionsverwaltung für Read Committed- und Snapshot-Transaktionen umfasst zwei Schritte:

  1. Festlegen eine oder beider der Datenbankoptionen READ_COMMITTED_SNAPSHOT und ALLOW_SNAPSHOT_ISOLATION auf ON.

  2. Festlegen der entsprechenden Transaktionsisolationsstufe in einer Anwendung:

    • Wenn die READ_COMMITTED_SNAPSHOT-Datenbankoption auf ON gesetzt ist, verwenden Transaktionen, die die Read Committed-Isolationsstufe festlegen, die Zeilenversionsverwaltung.

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

Wenn eine der beiden Datenbankoptionen READ_COMMITTED_SNAPSHOT oder ALLOW_SNAPSHOT_ISOLATION auf ON gesetzt ist, weist SQL Server Database Engine (Datenbankmodul) jeder Transaktion, die Daten bearbeitet, mithilfe der Zeilenversionsverwaltung eine Transaktionssequenznummer (XSN, Transaction Sequence Number) zu. Die Transaktionen starten zu dem Zeitpunkt, wenn eine BEGIN TRANSACTION-Anweisung ausgeführt wird. Allerdings startet die Transaktionssequenznummer mit dem ersten Lese- oder Schreibvorgang nach der BEGIN TRANSACTION-Anweisung. Die Transaktionssequenznummer wird bei jeder Zuweisung um eins erhöht.

Wenn entweder die Datenbankoption READ_COMMITTED_SNAPSHOT oder die Datenbankoption ALLOW_SNAPSHOT_ISOLATION auf ON gesetzt ist, werden logische Kopien (Versionen) für alle in der Datenbank erfolgten Datenänderungen aufbewahrt. Jedes Mal, wenn eine Zeile durch eine bestimmte Transaktion geändert wird, speichert die Instanz von Database Engine (Datenbankmodul) eine Version des zuvor durch ein Commit bestätigten Bilds der Zeile in tempdb. Jede Version wird mit der Transaktionssequenznummer der Transaktion markiert, von der die Änderung vorgenommen wurde. Die Versionen der geänderten Zeilen werden mithilfe einer Verknüpfungsliste verkettet. Der neueste Zeilenwert wird immer in der aktuellen Datenbank gespeichert und mit den im Versionsspeicher von tempdb gespeicherten Zeilenversionen verkettet.

HinweisHinweis

Beim Ändern großer Objekte (LOBs) wird nur das geänderte Fragment zum Versionsspeicher in tempdb kopiert.

Die Zeilenversionen werden lang genug aufbewahrt, um den Anforderungen von Transaktionen gerecht zu werden, die unter zeilenversionsbasierten Isolationsstufen ausgeführt werden. Database Engine (Datenbankmodul) verfolgt die früheste nützliche Transaktionssequenznummer und löscht in regelmäßigen Abständen alle Zeilenversionen, die mit Transaktionssequenznummern versehen sind, die unterhalb der frühesten nützlichen Sequenznummer liegen.

Wenn beide Datenbankoptionen auf OFF gesetzt sind, werden nur die durch Trigger oder MARS-Sitzungen geänderten Zeilen oder die durch ONLINE-Indizierungsvorgänge gelesenen Zeilen in die Versionsverwaltung einbezogen. Diese Zeilenversionen werden jedoch freigegeben, sobald sie nicht mehr benötigt werden. Ein im Hintergrund ausgeführter Thread entfernt in regelmäßigen Abständen alle veralteten Zeilenversionen.

HinweisHinweis

Für Transaktionen von kurzer Dauer kann eine Version einer geänderten Zeile im Pufferpool zwischengespeichert werden, ohne dass sie in die Datenträgerdateien der tempdb-Datenbank geschrieben wird. Wenn nur ein kurzfristiger Bedarf für die versionsverwaltete Zeile besteht, wird sie einfach aus dem Pufferpool gelöscht und verursacht dadurch nicht unbedingt E/A-Aufwand.

Verhalten beim Lesen von Daten

Wenn unter zeilenversionsbasierten Isolationsstufen ausgeführte Transaktionen Daten lesen, fordern sie keine freigegebenen Sperren (S) für die gelesenen Daten an und blockieren deshalb keine Transaktionen, bei denen Daten geändert werden. Außerdem wird der Aufwand für das Sperren von Ressourcen minimiert, weil nur eine reduzierte Anzahl von Sperren angefordert wird. Die Read Committed-Isolation mit Zeilenversionsverwaltung und die Snapshotisolation wurden entwickelt, um die Lesekonsistenz der versionsbasierten Daten auf Anweisungsebene bzw. auf Transaktionsebene zu gewährleisten.

Alle Abfragen, einschließlich Transaktionen, die in auf der Versionsverwaltung basierenden Isolationsstufen ausgeführt werden, richten Sperren vom Typ Sch-S (Schemastabilität) während der Kompilierung und der Ausführung ein. Deshalb werden Abfragen blockiert, wenn eine gleichzeitige Transaktion eine Sperre vom Typ Sch-M (Schemaänderung) für die Tabelle eingerichtet hat. So fordert beispielsweise ein DDL-Vorgang (Data Definition Language) eine Sperre vom Typ Sch-M an, bevor die Schemainformationen der Tabelle geändert werden. Abfragetransaktionen, einschließlich der Transaktionen, die eine auf der Zeilenversionsverwaltung basierende Isolationsstufe verwenden, werden beim Anfordern einer Sperre vom Typ Sch-S blockiert. Umgekehrt blockiert eine Abfrage mit einer Sperre vom Typ Sch-S eine gleichzeitige Transaktion, die eine Sperre vom Typ Sch-M anfordert. Weitere Informationen zum Verhalten von Sperren finden Sie unter Kompatibilität von Sperren (Datenbankmodul).

Wenn eine Transaktion mithilfe der Snapshotisolationsstufe gestartet wird, zeichnet die Instanz von Database Engine (Datenbankmodul) alle aktuell aktiven Transaktionen auf. Wenn die Snapshottransaktion eine Zeile liest, die über eine Versionskette verfügt, verfolgt Database Engine (Datenbankmodul) diese Kette und ruft die Zeile dort ab, wo sich die Transaktionssequenznummer befindet:

  • Am nächsten zur Sequenznummer der Snapshottransaktion, die die Zeile liest, jedoch unterhalb dieser Sequenznummer.

  • Nicht in der Liste der beim Start der Snapshottransaktion aktiven Transaktionen.

Die von einer Snapshottransaktion ausgeführten Lesevorgänge rufen die letzte Version jeder Zeile ab, für die zum Startzeitpunkt der Snapshottransaktion ein Commit erfolgt war. Damit wird ein transaktionskonsistenter Snapshot der Daten bereitgestellt, wie sie beim Start der Transaktion vorlagen.

Read Committed-Transaktionen mit Zeilenversionsverwaltung funktionieren auf sehr ähnliche Weise. Der Unterschied besteht darin, dass die Read Committed-Transaktion beim Auswählen der Zeilenversionen nicht ihre eigene Transaktionssequenznummer verwendet. Jedes Mal, wenn eine Anweisung gestartet wird, liest die Read Committed-Transaktion die letzte Transaktionssequenznummer, die für diese Instanz von Database Engine (Datenbankmodul) ausgegeben wurde. Das ist die Transaktionssequenznummer, die zum Auswählen der richtigen Zeilenversionen für diese Anweisung verwendet wird. Dadurch können Read Committed-Transaktionen einen Snapshot der Daten sehen, wie sie beim Start jeder Anweisung vorgelegen haben.

HinweisHinweis

Obwohl Read Committed-Transaktionen mit Zeilenversionsverwaltung eine im Hinblick auf Transaktionen konsistente Sicht der Daten auf Anweisungsebene bereitstellen, bleiben die von diesem Transaktionstyp generierten Zeilenversionen bzw. die Zeilenversionen, auf die dieser Transaktionstyp zugreift, bis zum Ende der Transaktion erhalten.

Verhalten beim Ändern von Daten

In einer Read Committed-Transaktion mit Zeilenversionsverwaltung erfolgt das Auswählen der zu aktualisierenden Zeilen durch Verwenden eines Blockierungsscans, bei dem eine Aktualisierungssperre (U) für die Daten beim Lesen der Datenwerte bewirkt wird. Das ist dasselbe Verhalten wie bei Read Committed-Transaktionen ohne Zeilenversionsverwaltung. Wenn die Datenzeile nicht dem Aktualisierungskriterium entspricht, wird die Aktualisierungssperre für diese Zeile aufgehoben, und die nächste Zeile wird gesperrt und gescannt.

Transaktionen, die mit der Snapshotisolationsstufe ausgeführt werden, verwenden eine optimistische Vorgehensweise bei der Datenänderung, indem Sperren für Daten aktiviert werden, bevor die Änderung vorgenommen wird, damit Einschränkungen erzwungen werden. Andernfalls werden erst dann Sperren für Daten aktiviert, wenn die Daten geändert werden sollen. Wenn eine Datenzeile dem Aktualisierungskriterium entspricht, überprüft die Snapshottransaktion, dass die Datenzeile nicht durch eine parallele Transaktion geändert wurde, für die nach dem Start der Snapshottransaktion ein Commit erfolgte. Wenn die Datenzeile außerhalb der Snapshottransaktion geändert wurde, tritt ein Aktualisierungskonflikt auf, und die Snapshottransaktion wird beendet. Der Aktualisierungskonflikt wird von Database Engine (Datenbankmodul) behandelt, und es gibt keinerlei Möglichkeit, die Erkennung von Aktualisierungskonflikten zu deaktivieren.

HinweisHinweis

Aktualisierungsvorgänge, die mit der Snapshotisolationsstufe gestartet werden, werden unter der Read Committed-Isolation ausgeführt, wenn die Snapshottransaktion auf eines der folgenden Elemente zugreift:

Eine Tabelle mit einer FOREIGN KEY-Einschränkung.

Eine Tabelle, auf die in der FOREIGN KEY-Einschränkung einer anderen Tabelle verwiesen wird.

Eine indizierte Sicht, die auf mehrere Tabellen verweist.

Allerdings wird der Aktualisierungsvorgang selbst unter diesen Bedingungen fortgesetzt, um zu überprüfen, dass die Daten nicht durch eine andere Transaktion geändert wurden. Wenn die Daten durch eine andere Transaktion geändert wurden, erkennt die Snapshottransaktion einen Aktualisierungskonflikt und wird beendet.

Gesamtverhalten

In der folgenden Tabelle werden die Unterschiede zwischen der Snapshotisolation und der Read Committed-Isolation mit Zeilenversionsverwaltung zusammengefasst.

Eigenschaft

Read Committed-Isolationsstufe mit Zeilenversionsverwaltung

Snapshotisolationsstufe

Die Datenbankoption, die auf ON gesetzt sein muss, um die erforderliche Unterstützung zu aktivieren.

READ_COMMITTED_SNAPSHOT

ALLOW_SNAPSHOT_ISOLATION

Wie eine Sitzung den speziellen Typ der Zeilenversionsverwaltung anfordert.

Verwenden Sie die standardmäßige Read Committed-Isolationsstufe, oder führen Sie die SET TRANSACTION ISOLATION LEVEL-Anweisung aus, um die READ COMMITTED-Isolationsstufe anzugeben. Das kann nach dem Start der Transaktion durchgeführt werden.

Erfordert, dass SET TRANSACTION ISOLATION LEVEL zum Angeben der SNAPSHOT-Isolationsstufe vor dem Start der Transaktion ausgeführt wird.

Die von den Anweisungen gelesene Datenversion.

Alle Daten, für die vor dem Start jeder Anweisung ein Commit erfolgte.

Alle Daten, für die vor dem Start jeder Transaktion ein Commit erfolgte.

Wie Aktualisierungen behandelt werden.

Kehrt von den Zeilenversionen zu den tatsächlichen Daten zurück, um die zu aktualisierenden Zeilen auszuwählen, und verwendet Aktualisierungssperren für die ausgewählten Datenzeilen. Aktiviert exklusive Sperren für die tatsächlichen Datenzeilen, die geändert werden sollen. Keine Erkennung von Aktualisierungskonflikten.

Verwendet die Zeilenversionen zum Auswählen der zu aktualisierenden Zeilen. Versucht, eine exklusive Sperre für die tatsächliche Datenzeile zu aktivieren, die geändert werden soll. Wenn die Daten durch eine andere Transaktion geändert wurden, tritt ein Aktualisierungskonflikt auf, und die Snapshottransaktion wird beendet.

Erkennung von Aktualisierungskonflikten.

Keine.

Integrierte Unterstützung. Kann nicht deaktiviert werden.