Wissen

Praxis-Artikel und Buchkapitel zu SQL-Performance, Sicherheit und Hochverfügbarkeit – alle frei verfügbar.

Beratung

Festpreis-Analyse mit Bericht und Handlungsempfehlung – oder strategische Begleitung bei Architektur, Migration und Hochverfügbarkeit.

Fachbücher

Die fünfbändige Reihe „Ulis SQL-Bibliothek“ – Band 1 verfügbar. Leseprobe herunterladen!

Tools

UB.SimSQL: SQL-Server-Lastsimulator mit regelbasierten Konfigurationsempfehlungen. Lokal, ohne Cloud, ohne Abo.

Schulungen

Online-Workshops zu Performance, Sicherheit und Entwicklung – kompakt, hands-on, ohne MOC-Folienschlacht.

Row-Versioning und Snapshot Isolation: – SQL Server Performance

von

Dieser Artikel ist ein Kapitel aus:
SQL Server Performance & Troubleshooting
Praxisleitfaden, ca. 600 Seiten

[ Hier bei Amazon bestellen ]
[ Mehr zum Buch ]

Row-Versioning und Snapshot Isolation:

Zeitreisen für Datenbankabfragen — ohne Blocking

Es gibt ein Problem, das so alt ist wie relationale Datenbanken selbst: Lesende Transaktionen blockieren schreibende Transaktionen — oder umgekehrt. Der klassische Lösungsansatz war jahrzehntelang entweder Warten (korrekt, aber langsam) oder NOLOCK (schnell, aber gefährlich falsch). Row Versioning ist die elegante dritte Option, die SQL Server seit Version 2005 kennt und die in modernen OLTP-Systemen eigentlich Standard sein sollte.

In diesem Kapitel schauen wir uns an, wie Row Versioning technisch funktioniert, was RCSI und Snapshot Isolation unterscheidet, welchen Preis du dafür zahlst — und warum der Preis fast immer die Investition wert ist. Voraussetzung: Du hast Kapitel 27 (Isolation Levels) gelesen und weißt, warum READ UNCOMMITTED keine Lösung ist. Und aus Kapitel 28 (Locking aus Entwicklersicht) weißt du, wie klassisches Locking die Nebenläufigkeit einschränkt.

Das Problem: Reader und Writer im Clinch

SQL Servers Standard-Isolationsebene ist READ COMMITTED. Das klingt vernünftig — du liest nur committete Daten, keine schmutzigen Halbzustände. Der Haken: "Read Committed" bedeutet klassischerweise, dass ein shared lock (S-Lock) für die Dauer des Lesevorgangs gehalten wird. Und ein S-Lock ist inkompatibel mit einem exclusive lock (X-Lock), den ein schreibender Prozess hält.

Das Ergebnis ist so vorhersehbar wie ärgerlich: Dein Report-Query läuft gerade über die Auftragstabelle — 500.000 Zeilen, dauert vier Sekunden. In dieser Zeit kann niemand in diese Tabelle schreiben, ohne zu warten. Andersherum: Eine große Batch-Verarbeitung hält X-Locks auf tausend Zeilen — dein Dashboard-Query steht Schlange.

Der reflexartige Griff zu NOLOCK (READ UNCOMMITTED) löst das Blocking-Problem, schafft aber neue: Du liest Daten, die gleich wieder zurückgerollt werden. Du liest Zeilen doppelt, weil eine Seite gerade umorganisiert wird. Du liest Zeilen gar nicht, weil sie durch eine Seitenteilung "verschwinden". Das ist kein Tradeoff — das ist ein Fehler, der sich manchmal stundenlang nicht bemerkbar macht und dann die Buchhaltung aufmischt.

 

Warnung: NOLOCK ist kein Performance-Feature

SELECT … WITH (NOLOCK) löst keine Blocking-Probleme — es ignoriert sie. Du bekommst möglicherweise falsche Ergebnisse: doppelt gelesene Zeilen, nicht gelesene Zeilen, Phantom-Daten aus zurückgerollten Transaktionen.

Jedes System, das NOLOCK produktiv einsetzt, weil "es sonst zu langsam ist", braucht eigentlich Row Versioning. Der einzig legitime Einsatz von NOLOCK ist die schnelle Schätzabfrage (z. B. ungefähre Row-Counts) — und auch das solltest du dokumentieren.

 

Die elegante Lösung heißt Row Versioning: Statt Reader und Writer gegeneinander zu sperren, bekommt jeder Leser eine konsistente Momentaufnahme der Daten — die letzte committete Version, ohne irgendjemanden zu blockieren.

 

Definition: Row Versioning

Row Versioning ist ein Mechanismus, bei dem SQL Server bei jeder Änderung einer Zeile die alte Version in einem zentralen Speicherbereich (Version Store) in TempDB aufbewahrt. Lesende Transaktionen, die eine ältere Version benötigen, finden sie dort — ohne den aktuellen Schreibvorgang zu blockieren und ohne selbst blockiert zu werden.

 

Wie Row Versioning technisch funktioniert

Wenn RCSI oder Snapshot Isolation für eine Datenbank aktiviert ist, passiert bei jeder schreibenden Operation folgendes: SQL Server hängt an jede Zeile in der Datendatei einen 14-Byte-Anhang — den sogenannten Version Tag. Dieser enthält die Transaktionssequenznummer (XSN) der letzten Transaktion, die diese Zeile verändert hat, plus einen Zeiger in den Version Store.

Wenn eine Transaktion eine Zeile ändert (UPDATE oder DELETE), kopiert SQL Server die alte Version dieser Zeile in den Version Store — einem speziellen Bereich in TempDB. Die neue Version verbleibt in der Datendatei und bekommt einen aktualisierten Version Tag. Der Version Store in TempDB ist damit eine Art Versionsverlauf: Je länger Transaktionen laufen, desto mehr alte Versionen sammeln sich dort an.

Eine lesende Transaktion, die eine bestimmte Version braucht (z. B. den Zustand von vor dem aktuellen UPDATE), schaut in den Version Tag der Zeile. Wenn die dort gespeicherte XSN neuer ist als der eigene Transaktionszeitpunkt, folgt sie dem Zeiger in den Version Store und liest die ältere Version. Kein Lock, kein Warten — nur ein Pointer-Lookup in TempDB.

 

Hintergrund: Der 14-Byte-Overhead

Die 14 Byte pro Zeile (8 Byte XSN + 6 Byte Zeiger) klingen nach wenig — und sind es meistens auch. Bei einer Tabelle mit 100-Byte-Zeilen sind das 14% Overhead. Bei einer Tabelle mit 1.000-Byte-Zeilen sind es nur noch 1,4%. Der Overhead ist fix pro Zeile, nicht proportional zur Zeilengröße.

Kritischer ist die Auswirkung auf die Anzahl der Zeilen pro Datenseite (8 KB): Eine Seite mit 100-Byte-Zeilen fasst ca. 81 Zeilen — mit Version Tag nur noch ~70. Das kann bei sehr schmalen Tabellen spürbar sein. Für 99% der typischen OLTP-Tabellen ist es irrelevant.

Wichtig: Der 14-Byte-Tag wird nur hinzugefügt, wenn die Datenbank ALLOW_SNAPSHOT_ISOLATION ON oder READ_COMMITTED_SNAPSHOT ON hat. Ohne diese Einstellungen entsteht kein Overhead.

 

Der Version Store in TempDB wird regelmäßig bereinigt: SQL Server entfernt Versionen, wenn keine aktive Transaktion sie noch braucht. Das Aufräumen läuft im Hintergrund — aber, solange lange Transaktionen laufen, wächst der Version Store. Mehr dazu im Abschnitt über TempDB-Auswirkungen — und generell in Kapitel 13, das TempDB und den Version Store als eigenständiges Thema behandelt.

RCSI: Read Committed Snapshot Isolation

RCSI ist die praktischste Variante des Row Versioning. Du aktivierst eine datenbankweite Einstellung — und ab da liest jede READ COMMITTED-Abfrage automatisch aus dem Version Store, anstatt Locks zu setzen. Kein Applikationscode muss geändert werden. Bestehende Abfragen profitieren ohne jede Anpassung.

Die Semantik von RCSI: Jedes einzelne Statement liest den letzten committeten Zustand zum Zeitpunkt des Statement-Starts. Nicht zum Transaktionsbeginn — zum Statement-Beginn. Das ist ein wichtiger Unterschied zu Snapshot Isolation, dazu gleich mehr.

RCSI aktivieren — die korrekte Sequenz

RCSI zu aktivieren klingt einfach, hat aber eine Tücke: Der zweite Befehl braucht eine exklusive Verbindung zur Datenbank — alle anderen Sessions müssen raus. In Produktionsumgebungen ist das ein geplantes Wartungsfenster.

-- Schritt 1: Snapshot Isolation auf Serverebene erlauben
-- (Voraussetzung für den zweiten Befehl)
ALTER DATABASE [MeineDB]
    SET ALLOW_SNAPSHOT_ISOLATION ON;

 

-- Schritt 2: READ COMMITTED SNAPSHOT aktivieren
-- Achtung: Dieser Befehl braucht eine exklusive DB-Verbindung.
-- Alle anderen Sessions müssen vorher getrennt werden.
-- Im Hintergrund: SQL Server geht kurz in den Single-User-Mode
-- und konfiguriert die DB um. In Produktionssystemen unbedingt
-- in einem Wartungsfenster durchführen.
ALTER DATABASE [MeineDB]
    SET READ_COMMITTED_SNAPSHOT ON;

 

-- Prüfen ob RCSI und SI aktiv sind:
SELECT
    name,
    is_read_committed_snapshot_on,      -- 1 = RCSI aktiv
    snapshot_isolation_state,           -- 0 = OFF, 1 = ON, 2 = wird aktiviert, 3 = wird deaktiviert
    snapshot_isolation_state_desc
FROM sys.databases
WHERE name = 'MeineDB';

 

Tipp: RCSI auf Azure SQL Database

Auf Azure SQL Database und Azure SQL Managed Instance ist RCSI standardmäßig aktiviert — du musst nichts tun. Microsoft hat das zu Recht als sinnvollen Standard gesetzt. Wenn du also ein System von On-Prem nach Azure migrierst, ändert sich damit das Leseverhalten aller READ COMMITTED-Abfragen. Das ist fast immer positiv — aber beim Testen wissen sollte man es.

 

Nach der Aktivierung kannst du RCSI nicht einfach still wieder deaktivieren, ohne die Auswirkungen zu kennen: Alle Applikationen, die bisher konfliktfrei gelesen haben, werden wieder auf Locks stoßen. Falls du ein System geerbt hast und nicht weißt warum RCSI an oder aus ist — sys.databases sagt die Wahrheit.

Snapshot Isolation: Transaktionskonsistenz auf Knopfdruck

RCSI löst das Reader-Writer-Problem auf Statement-Ebene. Snapshot Isolation (SI) geht einen Schritt weiter: Du bekommst eine konsistente Sicht auf die gesamte Datenbank für die Dauer deiner Transaktion — zum Zeitpunkt des Transaktionsbeginns.

Das klingt nach einem kleinen Unterschied, ist aber für bestimmte Workloads fundamental. Stell dir einen Reporting-Query vor, der erst die Auftragstabelle liest, dann die Kundentabelle, dann die Artikeltabelle — drei separate Statements, die zusammen fünf Sekunden laufen. Mit RCSI sieht jedes Statement einen anderen Snapshot (den jeweils aktuellen Stand). Wenn zwischen den Statements Buchungen verbucht werden, kann die Summe leicht inkonsistent sein. Mit SI siehst du alle drei Statements zum exakt gleichen Zeitpunkt — der Zustand ist transaktionskonsistent.

Snapshot Isolation verwenden

-- Snapshot Isolation explizit für eine Transaktion verwenden.
-- Voraussetzung: ALLOW_SNAPSHOT_ISOLATION ON für die Datenbank.
-- (READ_COMMITTED_SNAPSHOT muss dafür NICHT aktiviert sein.)
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

 

BEGIN TRANSACTION;

 

-- Alle Reads in dieser Transaktion sehen den Zustand
-- von genau diesem Transaktionsbeginn — egal was danach passiert.
SELECT SUM(Betrag) FROM Auftraege WHERE Status = 'Offen';
SELECT COUNT(*) FROM Kunden WHERE Aktiv = 1;

 

-- Beide Statements sind konsistent zum gleichen Zeitpunkt.
COMMIT;

Update Conflicts: Das stille Risiko

Snapshot Isolation hat eine Eigenschaft, die RCSI nicht hat: Update Conflicts. Wenn zwei SI-Transaktionen gleichzeitig dieselbe Zeile ändern wollen, bricht SQL Server die zweite Transaktion mit Fehler 3960 ab — weil sie sonst die erste Änderung überschreiben würde, ohne sie zu kennen.

-- Fehler 3960: Snapshot isolation transaction aborted due to update conflict.
-- Das passiert, wenn Transaktion B eine Zeile ändert,
-- die Transaktion A seit Transaktionsbeginn bereits verändert hat.

 

-- Beispiel: Zwei Transaktionen ändern gleichzeitig denselben Auftrag.
-- Transaktion A: UPDATE Auftraege SET Status = 'Geliefert' WHERE AuftragID = 42
-- Transaktion B: UPDATE Auftraege SET Status = 'Storniert' WHERE AuftragID = 42

 

-- Wenn A zuerst committet: B bekommt Fehler 3960.
-- Die Applikation muss Fehler 3960 abfangen und die Transaktion wiederholen.

 

BEGIN TRY
    SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
    BEGIN TRANSACTION;
    -- ... Deine Änderungen ...
    COMMIT;
END TRY
BEGIN CATCH
    IF ERROR_NUMBER() = 3960
    BEGIN
        -- Transaktion wiederholen — der Konflikt ist transient
        ROLLBACK;
        -- Retry-Logik in der Applikation implementieren
    END
    ELSE
        THROW; -- Anderer Fehler: weitergeben
END CATCH

 

Hinweis: SI-Update-Conflicts in der Praxis

Update Conflicts unter SI klingen schlimmer als sie sind. In gut designten OLTP-Systemen sind Konflikte auf dieselbe Zeile selten. Reporting-Workloads unter SI schreiben sowieso nicht — da passiert gar nichts. Gefährlich werden Konflikte nur, wenn du SI für Anwendungen verwendest, die viele gleichzeitige Updates auf überlappende Zeilmengen machen.

Als Faustregel: RCSI für den allgemeinen OLTP-Betrieb, SI nur dann, wenn du explizit Transaktionskonsistenz über mehrere Statements hinweg brauchst — und, wenn du die Retry-Logik für Fehler 3960 implementiert hast.

 

RCSI vs. SI: Die Entscheidungshilfe

 

Eigenschaft

RCSI

Snapshot Isolation (SI)

Scope

Datenbankweit, automatisch

Per Transaktion, explizit

Snapshot-Zeitpunkt

Bei jedem Statement neu

Einmalig bei Transaktionsbeginn

Applikationsänderung nötig?

Nein — READ COMMITTED profitiert automatisch

Ja — SET TRANSACTION ISOLATION LEVEL SNAPSHOT

Update Conflicts möglich?

Nein

Ja (Fehler 3960)

Transaktionskonsistenz

Nur innerhalb eines Statements

Über die gesamte Transaktion

Wann verwenden

OLTP-Standard — fast immer die richtige Wahl

Reporting-Transaktionen, Konsistenzprüfungen, Batch-Auswertungen

TempDB-Belastung

Immer (jede schreibende Transaktion)

Immer (wenn SI aktiv)

Tab. 29-1: RCSI und SI im Direktvergleich

 

Die Faustregel für die Praxis: Aktiviere RCSI auf allen OLTP-Datenbanken und vergiss Snapshot Isolation erstmal. SI kommt ins Spiel, wenn du Reports schreibst, die mehrere Tabellen konsistent lesen müssen — oder, wenn du einen Batchjob hast, der einen langen, konsistenten Blick auf die Datenbank braucht, ohne andere zu blockieren.

Version Store: Was das mit TempDB macht

Nichts ist umsonst. Der Preis für Row Versioning ist TempDB-Last. Jede UPDATE- und DELETE-Operation in einer Datenbank mit RCSI oder SI schreibt die alte Zeilenversion in den Version Store — einen Bereich in TempDB. Je mehr gleichzeitige Schreibtransaktionen laufen, desto mehr landet dort. Je länger Transaktionen offen bleiben, desto länger bleibt der Inhalt erhalten.

Das ist kein Problem, solange TempDB ausreichend dimensioniert ist und Transaktionen kurz bleiben. Kapitel 13 behandelt TempDB und den Version Store als eigenständiges Monitoring-Thema — hier die wichtigsten Queries für den Überblick:

-- Version Store Größe pro Datenbank überwachen
-- Wenn dieser Wert unkontrolliert wächst, gibt es lange offene Transaktionen
SELECT
    database_name,
    reserved_space_kb / 1024.0          AS reserved_mb,
    used_space_kb / 1024.0              AS used_mb,
    reserved_space_kb - used_space_kb
        / 1024.0                        AS free_mb
FROM sys.dm_tran_version_store_space_usage
ORDER BY used_space_kb DESC;

 

-- Aktive Snapshot-Transaktionen identifizieren
-- Diese Transaktionen verhindern die Bereinigung des Version Store
SELECT
    t.transaction_id,
    t.transaction_sequence_num,         -- Der Snapshot-Zeitpunkt der Transaktion
    t.elapsed_time_seconds,             -- Wie lange läuft die Transaktion schon?
    DB_NAME(dt.database_id)             AS Datenbank,
    s.session_id,
    s.login_name,
    r.command,
    r.status
FROM sys.dm_tran_active_snapshot_database_transactions AS t
JOIN sys.dm_tran_database_transactions AS dt
    ON t.transaction_id = dt.transaction_id
LEFT JOIN sys.dm_exec_sessions AS s
    ON t.session_id = s.session_id
LEFT JOIN sys.dm_exec_requests AS r
    ON s.session_id = r.session_id
ORDER BY t.elapsed_time_seconds DESC;

Was du dort siehst: Alle Transaktionen, die aktuell einen Snapshot halten. Die Spalte elapsed_time_seconds ist dein wichtigster Indikator — eine Transaktion, die seit 3.600 Sekunden läuft (eine Stunde!), verhindert, dass SQL Server alle Versionen aus diesem Zeitraum bereinigt. Der Version Store wächst so lange weiter, wie die älteste aktive Snapshot-Transaktion lebt.

 

Praxisbeispiel: Musterwerk GmbH: RCSI-Aktivierung und TempDB-Planung

Bei Musterwerk GmbH (MWSQL01) haben wir RCSI auf der Hauptdatenbank aktiviert. Das Ergebnis war sofort messbar: LCK_M_S-Waits verschwanden aus den Top 5 der Wait Statistics. Blocking-Beschwerden der Fachabteilung gingen von täglich auf einmal pro Woche zurück.

Der Preis: TempDB wächst während der Stoßzeiten (9–12 Uhr und 14–17 Uhr) um durchschnittlich 1,8 GB. Das war eingeplant — TempDB war vorher auf einem separaten Volume mit 50 GB, der Version Store passt bequem rein.

Lektion: RCSI vorher in einer Lasttest-Umgebung aktivieren und den TempDB-Wachstum über den typischen Arbeitstag beobachten. "2 GB Wachstum" klingt nach viel — auf einem 200-GB-TempDB-Volume ist es nichts.

 

 

Praxisbeispiel: Sparfuchs & Partner: Kein RCSI, maximales Blocking

Bei Sparfuchs & Partner (BUCHSQL01) war RCSI nicht aktiviert — kein Zufall, sondern Symptom einer Grundhaltung: "Das haben wir nie gebraucht." Dafür hatten sie regelmäßige Blocking-Kaskaden, bei denen eine lange laufende Abfrage der Buchhaltungssoftware die gesamte Tabelle für andere Nutzer sperrte.

Die IO-Latenz auf der Spindel (p95: 312 ms) machte das Problem noch schlimmer: Lange IO-Zeiten bedeuten längere Lock-Haltezeiten — jeder wartet länger auf jeden. RCSI hätte den Reader-Writer-Konflikt eliminiert. Den IO-Engpass hätte es nicht gelöst — aber die Blocking-Symptome wären deutlich milder gewesen.

Sparfuchs ist ein Paradebeispiel dafür, wie mehrere Probleme sich gegenseitig verstärken. Kap 33 behandelt die vollständige Analyse.

 

Sonderfälle: Trigger und Linked Server

INSTEAD OF Trigger und RCSI

INSTEAD OF Trigger verhalten sich unter RCSI geringfügig anders als erwartet. Die INSERTED- und DELETED-Tabellen innerhalb eines INSTEAD OF Triggers können unter RCSI andere Versionen zurückgeben als unter klassischem Read Committed — konkret dann, wenn zwischen dem Original-Statement und dem Trigger-Lauf Änderungen eingetroffen sind. In der Praxis ist das selten ein Problem, aber bei komplexen Trigger-Logiken lohnt ein Test in einer RCSI-Umgebung.

AFTER Trigger sind davon nicht betroffen — die laufen nach der Änderung und sehen das Ergebnis konsistent. Wenn du auf AFTER Trigger setzt (was für die meisten Use Cases die richtige Wahl ist), gibt es kein Problem.

Linked Server und Snapshot Isolation

Snapshot Isolation funktioniert nicht über Linked Server — das ist eine bekannte Einschränkung. Wenn eine SI-Transaktion einen Linked-Server-Zugriff macht, wird der als READ COMMITTED ausgeführt, nicht als Snapshot. Das ist meistens kein Problem, aber, wenn du Transaktionskonsistenz über mehrere Datenbanken hinweg über Linked Server benötigst, musst du das im Design berücksichtigen.

 

Hinweis: Distributed Transactions und SI

Wenn eine Snapshot-Transaktion eine verteilte Transaktion (DTC) auslöst — z. B. über Linked Server mit BEGIN DISTRIBUTED TRANSACTION — gibt es Konflikte. SQL Server kann in diesem Fall Fehler 3950 oder ähnliche zurückgeben. SI und verteilte Transaktionen sind kein gutes Gespann. RCSI ist davon nicht betroffen: RCSI ändert nur das Leseverhalten, nicht das Transaktionsprotokoll.

 

Diagnose: Symptome, Messung, Fehlinterpretationen, Gegenmaßnahmen

 

Hinweis: Symptome — woran erkennst du das Problem?

• LCK_M_S-Waits dominieren die Wait Statistics: Reader warten auf Writer-Locks. Das ist das Kernsymptom eines fehlenden RCSI.

• Nutzer berichten über sporadisch "eingefrorene" Applikation: Buchungsmasken blockieren für 2–30 Sekunden — ein langer Query hält Locks, alle anderen warten.

• Blocking-Ketten in sys.dm_exec_requests: head_blocker hat einen X-Lock, 15 Sessions warten mit LCK_M_S.

• Version Store wächst unkontrolliert in TempDB: sys.dm_tran_version_store_space_usage zeigt > 1 GB — eine oder mehrere lange Transaktionen halten den Store offen.

• RCSI zwar aktiviert, aber TempDB läuft voll: Lange offene Transaktionen oder hohe Schreib-Last ohne ausreichende TempDB-Dimensionierung.

 

 

Tipp: So misst du das

Die zwei wichtigsten Queries für RCSI-Diagnose — direkt einsetzbar:

 

-- 1) RCSI-Status aller Datenbanken auf dem Server prüfen
SELECT
    name                                    AS Datenbank,
    is_read_committed_snapshot_on           AS RCSI_aktiv,
    snapshot_isolation_state_desc           AS SI_status,
    user_access_desc,
    state_desc
FROM sys.databases
WHERE database_id > 4                       -- Systemdatenbanken überspringen
ORDER BY name;

 

-- 2) Version Store Größe und älteste aktive Transaktion
SELECT
    v.database_name,
    v.reserved_space_kb / 1024              AS reserved_mb,
    v.used_space_kb / 1024                  AS used_mb,
    MAX(t.elapsed_time_seconds)             AS aelteste_transaktion_sek
FROM sys.dm_tran_version_store_space_usage AS v
LEFT JOIN sys.dm_tran_active_snapshot_database_transactions AS t
    ON DB_ID(v.database_name) = t.database_id
GROUP BY v.database_name, v.reserved_space_kb, v.used_space_kb
ORDER BY v.used_space_kb DESC;

 

Warnung: Typische Fehlinterpretationen

• "RCSI macht TempDB-Probleme": RCSI erhöht den TempDB-Bedarf — das stimmt. Aber "erhöht" bedeutet nicht "überläuft". Mit sauber dimensionierter TempDB (Kapitel 13) und kurzen Transaktionen ist der Version Store harmlos. Das Problem ist nicht RCSI, sondern zu kleine TempDB oder zu lange Transaktionen.

• "SI und RCSI sind dasselbe": Nein. RCSI ist datenbankweit und automatisch, SI ist per Transaktion und explizit. RCSI gibt dir den letzten committeten Stand zum Statement-Beginn, SI zum Transaktionsbeginn. Das macht bei Reports mit mehreren Statements einen Konsistenzunterschied.

• "14 Byte pro Zeile — das ist nichts": Bei einer Tabelle mit 80-Byte-Zeilen sind das 17,5% Overhead — nicht nichts. Bei einer 4-KB-Zeile ist es tatsächlich nichts. Vor der Aktivierung die schmalsten Tabellen mit den höchsten Row-Counts identifizieren und den Speicherbedarf hochrechnen.

• "RCSI löst alle Blocking-Probleme": RCSI löst Reader-Writer-Blocking. Writer-Writer-Blocking (zwei UPDATEs auf dieselbe Zeile) bleibt bestehen — das ist Datenkonsistenz, kein Bug.

 

 

Tipp: Erste Gegenmaßnahmen

1. RCSI in einer Testumgebung aktivieren und den TempDB-Wachstum über eine realistische Last (1 Stunde Stoßzeit) beobachten. Wenn TempDB um mehr als 20% der verfügbaren Kapazität wächst: TempDB-Volume vergrößern, bevor du in Produktion aktivierst.

2. Lange Transaktionen identifizieren, bevor du RCSI aktivierst: sys.dm_tran_active_snapshot_database_transactions nach elapsed_time_seconds sortieren. Transaktionen, die länger als 10 Minuten laufen, sind deine Hausaufgabe — entweder kürzen oder zumindest einplanen, dass der Version Store entsprechend groß wird.

3. LCK_M_S-Waits aus den Wait Statistics entfernen: Wenn LCK_M_S unter den Top 5 ist, ist RCSI wahrscheinlich der einfachste Fix. Berechne den Wert im Vergleich zur Baseline (Kapitel 9) — 20% LCK_M_S ist ein Alarm, 0,5% ist Hintergrausch.

4. Nach RCSI-Aktivierung: Wait Statistics für 48 Stunden beobachten. LCK_M_S sollte deutlich fallen. Falls TempDB-Waits (PAGELATCH_EX auf TempDB-Seiten) steigen: Version Store dimensionierung überprüfen.

 

Zusammenfassung

Row Versioning ist kein exotisches Feature für Spezialfälle — es ist die saubere Antwort auf das älteste Problem in relationalen Datenbanken: Reader und Writer sollen sich nicht gegenseitig blockieren. Die Implementierung als RCSI (datenbankweit, automatisch) oder Snapshot Isolation (per Transaktion, explizit) gibt dir die Flexibilität, für jeden Workload die richtige Wahl zu treffen.

Der Preis ist überschaubar: 14 Byte pro Zeile in der Datendatei und ein wachsender Version Store in TempDB — solange Transaktionen kurz sind und TempDB angemessen dimensioniert ist. Das ist ein Deal, den du in fast jedem OLTP-System guten Gewissens eingehen kannst.

Was Row Versioning nicht tut: Es löst keine Writer-Writer-Konflikte, keinen schlechten Index-Design und keine schlecht optimierten Abfragen. Es gibt Lesern eine konsistente Sicht auf die Daten, ohne andere zu blockieren — und das allein macht die meisten Blocking-Beschwerden in OLTP-Systemen deutlich seltener.

  • RCSI datenbankweit aktivieren — kein Applikationscode muss geändert werden
  • Snapshot Isolation für Transaktionen mit Konsistenzanforderungen über mehrere Statements
  • Version Store in TempDB überwachen: sys.dm_tran_version_store_space_usage
  • Lange Transaktionen sind der Feind des Version Store — und damit von TempDB
  • NOLOCK ist keine Alternative zu RCSI — es ist ein anderes Problem, das so aussieht wie eine Lösung
  • Fehler 3960 unter SI abfangen und Retry-Logik implementieren
  •  

    Das war das letzte Kapitel, das sich mit dem Fundament des Parallelitäts-Managements beschäftigt. Kapitel 30 wechselt die Perspektive ein letztes Mal: von SQL Server zu der Schicht, die fast alle modernen Applikationen davor hängen — ORMs und Applikationsdesign. Entity Framework, Lazy Loading, N+1-Problem, Connection Pooling: Alles, was dein sauber konfigurierter und gut indizierter SQL Server trotzdem in die Knie zwingt, wenn die Applikation falsch damit redet.

     

    Abb. 1: RCSI-Mechanismus: Versionskette in TempDB

     

    Kapitel 30