SQL Server Performance – Blocking und Deadlocks:

von | Apr. 18, 2026 | BookSqlPerf, UliBook | 0 Kommentare

Das ist ein Auszug aus meinem SQL Performance-Buch.

Beratungsangebot SQL Server.

Hier informieren!

SQL Performance-Analyse zum Festpreis!

Hier informieren!

Hier bei Amazon bestellen

Table of Contents
2
3

SQL Server Performance – Inhaltsübersicht

Blocking und Deadlocks:

Wenn Prozesse sich gegenseitig blockieren — und niemand mehr weiterkommt

Es ist 14:37 Uhr. Der Support-Kanal läuft heiß. "Die Anwendung hängt." "Ich kann nichts speichern." "Das Formular dreht sich ewig." Du öffnest SSMS und schaust in sys.dm_exec_requests — und da ist er: eine Blocking-Kette mit zwölf Sessions. Eine einzige offene Transaktion, die seit 23 Minuten wartet. Auf was wartet sie? Auf Session 57, die einen Lock hält und gerade — oh wunderbar — auf einen SELECT wartet, der auf Session 42 wartet, die seit 23 Minuten inaktiv ist. Weil die Kollegin in der Buchhaltung das Bearbeitungsfenster offen gelassen und ist Mittagessen gegangen.

Herzlich willkommen in der Welt des Blockings. Das ist kein exotisches Randszenario — das ist der Alltag auf nahezu jedem produktiven SQL Server. Blocking ist die häufigste Ursache dafür, dass Anwendungen "ohne erkennbaren Grund" langsam werden. Und Deadlocks sind das dramatische Geschwisterkind: Wenn zwei Transaktionen sich gegenseitig blockieren und keiner von beiden kommt weiter, schlägt SQL Server durch und rollt eine der beiden zurück.

Dieses Kapitel erklärt die Mechanismen dahinter, zeigt wie man Blocking und Deadlocks diagnostiziert, und vor allem: was man dagegen tut. Die vertiefende Behandlung der Isolation Levels folgt in Kapitel 27, das Locking aus Entwicklerperspektive in Kapitel 28, und Row Versioning als elegante Lösung für Read/Write-Konflikte in Kapitel 29. Aber fangen wir mit den Grundlagen an.

Locking-Grundlagen: Warum SQL Server Locks braucht

Locking ist kein Bug — es ist ein Feature. SQL Server ist ein Mehrbenutzersystem, und genau das ist das Problem: Wenn zwei Sessions gleichzeitig dieselbe Zeile lesen und schreiben, gibt es ohne Schutzmechanismus entweder Dirty Reads (Session B liest Daten, die Session A noch nicht committed hat), Lost Updates (beide schreiben gleichzeitig, einer überschreibt den anderen) oder Phantom Reads. Das ACID-Prinzip — Atomicity, Consistency, Isolation, Durability — verlangt, dass Transaktionen voneinander isoliert ablaufen. Locks sind das primäre Instrument dafür.

Die schlechte Nachricht: Locks bedeuten Wartezeiten. Die gute Nachricht: Richtig konfiguriert und mit sauberem Code halten sie sich in Grenzen, die kaum auffallen. In Kapitel 04 haben wir den Storage Engine und den Lock Manager als Teil der SQL Server-Architektur kennengelernt — hier sehen wir ihn bei der Arbeit.

Lock-Granularität: Was genau wird gesperrt?

SQL Server kann auf verschiedenen Ebenen sperren — vom einzelnen Schlüsselwert bis zur gesamten Datenbank. Faustregel: Je feingranularer die Sperre, desto mehr Parallelität ist möglich — aber desto mehr Speicher verbraucht die Lock-Verwaltung.

 

Granularität

Beschreibung

Typische Situation

RID (Row ID)

Einzelne Zeile in einem Heap

SELECT/UPDATE auf Heap-Tabelle

KEY

Einzelner Index-Schlüssel in B-Tree

SELECT/UPDATE auf Clustered Index

PAGE

Eine 8-KB-Datenseite (typisch 100–500 Zeilen)

Viele Zeilen auf einer Seite

EXTENT

Acht zusammenhängende Seiten (64 KB)

Selten, meist bei Bulk-Ops

TABLE

Gesamte Tabelle inkl. aller Indizes

Lock Escalation, DDL, TABLOCK

DATABASE

Gesamte Datenbank

ALTER DATABASE, Backup, Restore

Tabelle 14.1: Lock-Granularitäten in SQL Server

 

Für die tägliche Praxis relevant sind vor allem ROW/KEY-Locks (bei normalen DML-Operationen) und TABLE-Locks (bei Lock Escalation oder explizitem TABLOCK-Hint). PAGE-Locks entstehen als Zwischenstufe, sind aber selten direkt sichtbar.

Lock-Typen: Was wird wie gesperrt?

Lock-Granularität sagt wo gesperrt wird, Lock-Typ sagt wie. Die wichtigsten Typen:

 

Lock-Typ

Kürzel

Wer bekommt ihn?

Kompatibel mit

Shared

S

Lesende Operationen (SELECT)

S, U, IS

Exclusive

X

Schreibende Operationen (INSERT, UPDATE, DELETE)

Nichts

Update

U

Vor UPDATE: erst lesen, dann schreiben

S, IS

Intent Shared

IS

Parent-Level bei Row/Page-Level S-Lock

S, IS, IX, U, SIX

Intent Exclusive

IX

Parent-Level bei Row/Page-Level X-Lock

IS, IX

Shared Intent Exclusive

SIX

Tabelle lesen, einzelne Zeilen schreiben

IS

Tabelle 14.2: SQL Server Lock-Typen und Kompatibilität

 

Der X-Lock ist der Bösewicht in dieser Geschichte: Er ist mit keinem anderen Lock kompatibel. Solange eine UPDATE- oder DELETE-Transaktion einen X-Lock auf einer Zeile hält, muss jede andere Session — egal ob lesend oder schreibend — warten. Intent Locks (IS, IX) werden auf übergeordneten Ebenen gesetzt, damit der Lock Manager nicht jede einzelne Zeile prüfen muss: Ein IX auf der Tabelle signalisiert, dass irgendwo in dieser Tabelle ein X-Lock existiert.

Lock Compatibility Matrix

 

Beantragt →

S

X

U

IS

IX

Gehalten S

Ja

Nein

Ja

Ja

Nein

Gehalten X

Nein

Nein

Nein

Nein

Nein

Gehalten U

Ja

Nein

Nein

Ja

Nein

Gehalten IS

Ja

Nein

Ja

Ja

Ja

Gehalten IX

Nein

Nein

Nein

Ja

Ja

Tabelle 14.3: Lock Compatibility Matrix — Ja = kompatibel, Nein = Konflikt → Blocking

 

 

Hinweis: Intent Locks und die Baumstruktur

Intent Locks funktionieren wie ein Zettel an der Tür: "Hier drin ist jemand am Arbeiten." SQL Server setzt IS auf die Tabelle, wenn eine Zeile mit S gesperrt wird — damit kein anderer einen TABLE X-Lock beantragen kann, ohne vorher in den Konflikt zu laufen. Das spart dem Lock Manager massenhaft Arbeit.

 

Lock Escalation: Wenn zu viele Locks zu einem werden

SQL Server bevorzugt feingranulare Locks — aber Locks kosten Speicher. Pro Lock werden rund 64 bis 128 Byte verbraucht. Bei einem UPDATE das 50.000 Zeilen ändert, sind das schnell 3–6 MB nur für Lock-Verwaltung. Deshalb eskaliert SQL Server ab einer gewissen Schwelle automatisch auf Table Lock:

  • 5.000 Locks auf Zeilen- oder Seitenebene innerhalb einer einzelnen Anweisung, oder
  • 40% des dynamisch verfügbaren Lock-Speichers werden durch eine einzige Transaktion verbraucht
  • Die Konsequenz: Aus hunderten Row-Locks wird plötzlich ein einziger Table-Lock. Das spart Speicher — aber der Table-Lock blockiert nun alle anderen Sessions, die irgendetwas in dieser Tabelle tun wollen. Lock Escalation ist einer der am häufigsten übersehenen Blocking-Gründe in großen Datenbanken.

    Du kannst Lock Escalation auf Tabellenebene deaktivieren mit ALTER TABLE … SET (LOCK_ESCALATION = DISABLE) — aber das solltest du nur nach sorgfältiger Überlegung tun. Ohne Escalation riskierst du OOM-Situationen im Lock Manager bei großen Bulk-Operationen. Verweis auf Kapitel 27: Dort behandeln wir Isolation Levels als alternativen Ansatz, um Lock Escalation zu vermeiden.

    Blocking: Das tägliche Leiden

    Blocking entsteht, wenn Session A einen Lock beantragt, den Session B bereits hält — und B diesen Lock noch nicht freigegeben hat. Session A schläft einfach ein (SUSPENDED) und wartet. Das klingt harmlos, ist es aber nicht wenn:

  • Die blockierte Session selbst wieder andere Sessions blockiert — Blocking-Kette
  • B sehr lange braucht, um seinen Lock freizugeben (offene Transaktion, Netzwerkproblem)
  • Hunderte von Sessions in der Kette hängen und die Anwendung komplett einfriert
  • Wichtig: Blocking ist per se kein Fehler. Es ist Korrektheit. SQL Server sichert damit die Datenkonsistenz. Unnötiges Blocking — durch fehlende Indizes, zu lange Transaktionen oder schlechtes Applikationsdesign — ist das Performance-Problem. Der Unterschied liegt im Wort "unnötig".

    Blocking-Ketten: Head Blocker und seine Opfer

    In einer Blocking-Kette gibt es immer einen Head Blocker: die Session, die niemanden blockiert, aber selbst einen Lock hält, auf den alle anderen warten. Das Schema:

    — Blocking-Kette (vereinfacht):

    Session 57: RUNNING — hält X-Lock auf Tabelle Bestellungen, Zeile 4711

    ↓ blockiert

    Session 63: SUSPENDED — wartet auf S-Lock, Bestellungen Zeile 4711

    ↓ blockiert (indirekt)

    Session 71: SUSPENDED — wartet auf U-Lock, Bestellungen Zeile 4711

    ↓ blockiert (indirekt)

    Session 84: SUSPENDED — wartet auf S-Lock, Bestellungen Zeile 4711

     

    — Head Blocker: Session 57 — alle anderen sind Opfer

    — Lösung: Session 57 commiten/rollbacken lassen oder killen (KILL 57)

    Der Head Blocker ist nicht zwangsläufig der Böse — oft hat er einfach ein schlechtes Los gezogen (lange Transaktion, nötiger Lauf). Aber er ist die Wurzel des Problems. Alle anderen Sessions freizugeben bringt nichts — solange Session 57 seinen Lock hält, ist die Situation dieselbe.

    Wie lange ist zu lang? Richtwerte für Blocking-Wartezeiten

     

    Wartezeit

    Bewertung

    Maßnahme

    < 1 Sekunde

    Normal — expected behavior

    Keine

    1–5 Sekunden

    Akzeptabel bei Write-heavy Workloads

    Beobachten, Baseline aufnehmen

    5–30 Sekunden

    Auffällig — sollte untersucht werden

    Head Blocker identifizieren, Root Cause prüfen

    > 30 Sekunden

    Kritisch — Nutzer merken es definitiv

    Sofort eskalieren, KILL erwägen

    > 5 Minuten

    Alarm — Anwendung ist praktisch eingefroren

    Notfallmaßnahmen, Management informieren

    Tabelle 14.4: Bewertungsraster für Blocking-Wartezeiten

     

    Diese Richtwerte gelten für OLTP-Systeme. Bei Batch-Verarbeitung nachts sind längere Blocking-Zeiten oft akzeptabel, weil keine Nutzer warten. Baseline ist entscheidend: Was auf MWSQL01 (Musterwerk GmbH) normal ist, kann bei Trendforge (Kap. 34) schon kritisch sein. Zur Baseline-Erhebung: Kapitel 09.

    Wait Types beim Blocking

    In sys.dm_os_wait_stats tauchen Blocking-Probleme unter LCK_M_*-Wait-Types auf. Die wichtigsten:

     

    Wait Type

    Bedeutung

    Häufigster Auslöser

    LCK_M_S

    Warten auf Shared Lock

    X-Lock einer anderen Transaktion

    LCK_M_X

    Warten auf Exclusive Lock

    S- oder X-Lock einer anderen Transaktion

    LCK_M_U

    Warten auf Update Lock

    Konkurrierendes UPDATE

    LCK_M_IS

    Warten auf Intent Shared

    Tabellen-Lock einer anderen Session

    LCK_M_IX

    Warten auf Intent Exclusive

    Tabellen-Lock einer anderen Session

    LCK_M_SCH_M

    Warten auf Schema Modification Lock

    DDL-Operation (ALTER TABLE, etc.)

    Tabelle 14.5: Lock-Wait-Types und ihre Auslöser

     

    LCK_M_S mit hoher Wartezeit ist das klassische Symptom für Read/Write-Contention — Lesende Sessions warten auf eine schreibende Transaktion. Hier ist RCSI (READ COMMITTED SNAPSHOT ISOLATION) oft die richtige Antwort, nicht das Schärfen der Axt. Mehr dazu in Kapitel 29.

    Blocking diagnostizieren: Wer blockt wen?

    Die erste Frage bei einem Blocking-Alarm ist immer: Wer ist der Head Blocker, und was tut er gerade? Die DMVs liefern die Antwort in Sekunden.

    Die Kern-Query: Blocking-Kette auf einen Blick

    — Vollständige Blocking-Diagnose: Head Blocker und Opfer

    — Zeigt die gesamte Kette mit Wartezeiten und aktuellen Statements

    SELECT

    r.session_id AS blockierte_session,

    r.blocking_session_id AS blockiert_durch,

    r.wait_type,

    r.wait_time / 1000.0 AS wartezeit_sek,

    r.status,

    — Was macht die blockierte Session gerade?

    SUBSTRING(qt.text,

    r.statement_start_offset / 2 + 1,

    CASE WHEN r.statement_end_offset = -1

    THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2

    ELSE r.statement_end_offset

    END – r.statement_start_offset) / 2 + 1

    AS aktuelles_statement,

    — Und was tut der Head Blocker?

    blocker_qt.text AS head_blocker_statement,

    s.login_name,

    s.host_name,

    s.program_name

    FROM sys.dm_exec_requests AS r

    CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS qt

    JOIN sys.dm_exec_sessions AS s

    ON r.session_id = s.session_id

    — Blocker-Statement via Subquery holen

    OUTER APPLY (

    SELECT qt2.text

    FROM sys.dm_exec_requests r2

    CROSS APPLY sys.dm_exec_sql_text(r2.sql_handle) qt2

    WHERE r2.session_id = r.blocking_session_id

    ) AS blocker_qt

    WHERE r.blocking_session_id IS NOT NULL — nur blockierte Sessions

    AND r.blocking_session_id > 0

    ORDER BY r.wait_time DESC; — längste Wartezeit zuerst

    Diese Query ist dein erstes Werkzeug bei jedem Blocking-Alarm. Sie zeigt dir sofort: Wer wartet, wie lange schon, auf wen — und was beide Sessions gerade machen. In 80% der Fälle ist das Statement des Head Blockers der Schlüssel zur Ursache.

    Welche Locks hält wer? sys.dm_tran_locks

    — Aktuelle Lock-Bestände pro Session — was hält wer gerade?

    — Nützlich, um Lock Escalation zu erkennen (resource_type = TABLE bei Row-Locks)

    SELECT

    l.request_session_id AS session_id,

    l.resource_type, — RID, KEY, PAGE, TABLE, DATABASE …

    l.resource_subtype,

    l.resource_database_id,

    DB_NAME(l.resource_database_id) AS datenbankname,

    l.resource_description, — konkrete Ressource (Seiten-ID, Schlüssel-Hash etc.)

    l.request_mode, — S, X, U, IS, IX …

    l.request_status, — GRANT = hält er, WAIT = wartet er

    l.request_type

    FROM sys.dm_tran_locks AS l

    WHERE l.request_session_id > 50 — System-Sessions ausblenden

    AND l.request_status IN ('GRANT', 'WAIT')

    ORDER BY l.request_session_id, l.request_mode;

    Offene Transaktionen finden: Wer hat BEGIN TRAN vergessen?

    — Offene Transaktionen — der häufigste Head-Blocker-Grund

    — open_transaction_count > 0 und status = sleeping = Alarm!

    SELECT

    s.session_id,

    s.status, — sleeping = nichts tut, aber Transaktion offen

    s.open_transaction_count, — > 0 = Transaktion nicht committed

    s.last_request_end_time, — wann war die letzte Aktivität?

    DATEDIFF(MINUTE, s.last_request_end_time, GETDATE()) AS minuten_inaktiv,

    s.login_name,

    s.host_name,

    s.program_name,

    — Letztes ausgeführtes Statement dieser Session

    qt.text AS letztes_statement

    FROM sys.dm_exec_sessions AS s

    OUTER APPLY sys.dm_exec_sql_text(s.most_recent_sql_handle) AS qt

    WHERE s.open_transaction_count > 0

    AND s.session_id > 50 — keine System-Sessions

    ORDER BY s.open_transaction_count DESC, minuten_inaktiv DESC;

    Eine Session mit status = sleeping und open_transaction_count > 0 ist der klassische Fall: Eine Transaktion wurde geöffnet, das Statement lief durch, aber der COMMIT oder ROLLBACK fehlt. Das Ergebnis: Der Lock lebt weiter, die Locks wachsen, und irgendwann hängt die halbe Anwendung. Bei Musterwerk GmbH (Kapitel 32) haben wir genau dieses Muster: Eine alte .NET-Anwendung, die bei einer Exception den Connection Pool zurückgibt, ohne die offene Transaktion abzuschließen. Klassiker.

    Blocked Process Report via Extended Events

    Für Blocking-Monitoring im laufenden Betrieb ist der Blocked Process Report das richtige Instrument. Er wird automatisch ausgelöst, wenn eine Session länger als einen konfigurierbaren Schwellwert blockiert ist. Zuerst muss der Schwellwert gesetzt werden — Standard ist 0 (= deaktiviert):

    — Blocked Process Report aktivieren und Schwellwert setzen

    — Wert in Sekunden — 5 bedeutet: Report ab 5 Sekunden Blocking

    EXEC sp_configure 'show advanced options', 1;

    RECONFIGURE;

    EXEC sp_configure 'blocked process threshold (s)', 5;

    RECONFIGURE;

     

    — Prüfen ob aktiv:

    SELECT name, value_in_use

    FROM sys.configurations

    WHERE name = 'blocked process threshold (s)';

    Die Extended Event Session zur Erfassung des Blocked Process Report kannst du direkt aus Kapitel 08 übernehmen. Das Event heißt sqlserver.blocked_process_report und liefert einen XML-Block mit dem blockierten und dem blockierenden Statement samt Lock-Details.

    Blocking-Ursachen: Die üblichen Verdächtigen

    Blocking entsteht nicht aus dem Nichts. Hinter jedem Blocking-Problem steckt eine konkrete Ursache — meistens eine von diesen:

    Lange Transaktionen

    Der Klassiker. Jemand öffnet eine Transaktion, liest und schreibt Daten — und irgendwann passiert etwas Unerwartetes: Ein Fehler, eine Exception, ein Netzwerkproblem, oder die Anwendung wartet auf eine Benutzereingabe während die Transaktion offen ist. Die Locks bleiben gesetzt, bis der COMMIT oder ROLLBACK kommt. Oder bis du ein KILL absetzt.

     

    Warnung: Transaktionen und Benutzerinteraktion

    Niemals eine Transaktion offen lassen, während auf Benutzereingabe gewartet wird. Das ist der klassische Designfehler: BEGIN TRAN → Daten lesen → Dialog anzeigen → warten auf Klick → COMMIT. Der Benutzer geht Kaffee holen. Kaffee ist leer. Er macht Mittagspause. Die Transaktion läuft. Die Blocking-Kette wächst.

     

    Fehlende Indizes erzwingen Lock Escalation

    Ein UPDATE ohne passenden Index macht einen Table Scan. Table Scan = Locks auf jeder Zeile, jeder Seite, die gelesen wird — auch, wenn am Ende nur eine Zeile geändert wird. Irgendwann eskaliert das auf TABLE-Lock. Die gesamte Tabelle ist gesperrt, bis das UPDATE fertig ist. Bei Sparfuchs & Partner (BUCHSQL01) haben wir das im Extremformat gesehen: 97% Index-Fragmentierung und fehlende Indizes auf FK-Spalten — ein UPDATE dauerte 40 Sekunden und sperrte dabei die komplette Bestelltabelle (Kapitel 33).

    SELECT * liest mehr als nötig

    Ein SELECT * liest alle Spalten einer Zeile. Mehr Daten pro Zeile = mehr Seiten gelesen = mehr Locks = höheres Eskalationsrisiko. Dazu kommt: mehr IO, mehr Memory Grant (Kapitel 12), mehr Netzwerktraffic. SELECT * ist aus vielen Gründen eine schlechte Idee — Locking ist einer davon.

    Lock Escalation durch Massen-DML

    Ein DELETE das 200.000 Zeilen auf einmal löscht, eskaliert fast sicher zu einem Table-Lock. Besser: Löschen in Batches von je 1.000–5.000 Zeilen mit WAITFOR DELAY zwischen den Batches. Das gibt anderen Sessions die Chance, zwischendurch Locks zu bekommen. Batch-Verarbeitung als Designprinzip behandeln wir in Kapitel 25.

    Applikationsfehler: Offene Transaktionen nach Exceptions

    In .NET-Code häufig zu sehen: Eine SqlConnection wird in einen Using-Block gepackt (gut), aber die SqlTransaction nicht. Bei einer Exception wird die Connection zurück in den Pool gegeben — mit aktiver Transaktion. SQL Server setzt die Verbindung zurück, wenn die nächste Anfrage kommt, aber das kann Millisekunden dauern. In dieser Zeit leben die Locks weiter. Bei Connection Pools mit hundert Verbindungen summiert sich das.

    Gegenmaßnahmen: Was wirklich hilft — und was nicht

    NOLOCK: Die falsche Antwort auf die richtige Frage

    Du wirst ihn sehen. Überall. In Legacy-Code, in Stack-Overflow-Antworten, in genervten Kommentaren von DBA-Kollegen: "Füg einfach WITH(NOLOCK) hinzu, dann blockiert es nicht mehr." Das ist wie das Deaktivieren des Airbags um das Warnlicht auszuschalten.

    NOLOCK (= READ UNCOMMITTED) liest Daten, die noch nicht committed sind — Dirty Reads. Das bedeutet:

  • Du liest Daten aus einer Transaktion, die später zurückgerollt wird — die Daten existierten nie
  • Du kannst dieselbe Zeile zweimal lesen oder eine Zeile gar nicht sehen (Phantom Reads)
  • Bei Index-Reorganisationen oder Page Splits kann ein NOLOCK-Scan mit Fehler 605 enden ("Could not continue scan with NOLOCK due to data movement") — ein tatsächlicher Laufzeitfehler
  • In Finanz- oder Buchhaltungsanwendungen sind Dirty Reads schlicht inakzeptabel
  •  

    Warnung: NOLOCK ist kein Performance-Feature

    NOLOCK eliminiert nicht das Blocking — es gibt den Lock einfach auf und liest ungefiltert. Die Inkonsistenz die daraus folgt ist kein theoretisches Problem. Bei Trendforge Digital (TFSQL01) haben wir Berichte gesehen, die falsche Summen auswiesen, weil NOLOCK mitten in einem Multi-Step-UPDATE gelesen hatte. Die Erklärung gegenüber dem Kunden war unangenehm.

     

    READ COMMITTED SNAPSHOT ISOLATION (RCSI): Die richtige Antwort

    RCSI ist die elegante Lösung für das häufigste Blocking-Muster: Read/Write-Konflikte. Statt Shared Locks für lesende Operationen zu setzen, liest SQL Server im RCSI-Modus aus dem Versionsstore in TempDB — einen "Snapshot" der letzten committed Version der Zeile. Leser blockieren Schreiber nicht mehr, Schreiber blockieren Leser nicht mehr.

    — RCSI für eine Datenbank aktivieren

    — Einmalig, danach gilt READ COMMITTED automatisch als "RCSI"

    — Wichtig: kurz werden S-Locks durch Versioning ersetzt — TempDB-Auswirkung prüfen!

    ALTER DATABASE [MeineDB]

    SET READ_COMMITTED_SNAPSHOT ON

    WITH ROLLBACK IMMEDIATE; — oder WITH NO_WAIT für eine saubere Umschaltung im Wartungsfenster

     

    — Prüfen ob RCSI aktiv ist:

    SELECT name, is_read_committed_snapshot_on

    FROM sys.databases

    WHERE name = 'MeineDB';

    Vorsicht: RCSI erzeugt Row Versions in TempDB. Mehr Last auf TempDB — das ist der Trade-off. Kapitel 13 (TempDB) und Kapitel 29 (Row Versioning) behandeln das ausführlich. Aber für die meisten OLTP-Systeme überwiegt der Vorteil: Read/Write-Blocking verschwindet nahezu vollständig.

    Kürzere Transaktionen: Das wichtigste Mittel

    Die effektivste Maßnahme gegen Blocking hat keinen coolen Namen: Transaktionen so kurz wie möglich halten. Nur das in die Transaktion packen, was wirklich atomar sein muss. Nichts in eine Transaktion aufnehmen was nach draußen kommuniziert (REST-Calls, Dateizugriffe, Benutzereingaben). Und: immer einen TRY/CATCH mit ROLLBACK im Fehlerfall. Klingt banal, rettet Produktionssysteme.

    Lock Timeout als Sicherheitsnetz

    — SET LOCK_TIMEOUT: Wie lange soll eine Session auf einen Lock warten?

    — Wert in Millisekunden, -1 = unendlich (Standard)

    — 5000 = 5 Sekunden, dann Error 1222 statt ewiges Warten

     

    — Auf Session-Ebene setzen (bleibt bis zur nächsten Verbindung aktiv):

    SET LOCK_TIMEOUT 5000;

     

    — Test:

    BEGIN TRAN;

    SELECT * FROM dbo.Bestellungen WITH (TABLOCK, HOLDLOCK);

    — In einer anderen Session jetzt SELECT … WITH (XLOCK) versuchen

    — → Error 1222 nach 5 Sekunden

    ROLLBACK;

    LOCK_TIMEOUT ist kein Ersatz für vernünftiges Transaktionsdesign, aber ein gutes Sicherheitsnetz: Statt, dass eine Session stundenlang wartet und eine Blocking-Kette wächst, bekommt die Anwendung einen Fehler zurück und kann ihn sinnvoll behandeln (Retry, Fehlermeldung, Escalation).

    Deadlocks: Wenn sich zwei gegenseitig blockieren

    Deadlock ist das, was passiert, wenn Blocking in beide Richtungen geht: Session A wartet auf Session B, und Session B wartet auf Session A. Beide sind SUSPENDED, keiner macht einen Schritt weiter. Ohne externe Hilfe würden sie ewig warten. SQL Server erkennt das — und greift ein.

    Der Lock Monitor (ein interner Hintergrund-Thread) prüft alle 5 Sekunden auf Deadlock-Situationen. Er baut den Lock-Wartegrafen auf und sucht nach Zyklen. Findet er einen, wählt er ein Opfer (Victim) nach einem simplen Prinzip: rollback the cheapest. Die Transaktion mit den kleinsten Rollback-Kosten (gemessen in Log-Einträgen) wird zurückgerollt. Das Opfer bekommt Error 1205: "Transaction (Process ID X) was deadlocked on lock resources with another process and has been chosen as the deadlock victim."

    Der klassische Deadlock: Zwei Tabellen in falscher Reihenfolge

    Das häufigste Deadlock-Muster ist simpel. Zwei Transaktionen greifen auf dieselben zwei Tabellen zu — aber in unterschiedlicher Reihenfolge:

    — Transaktion A (Session 55):

    BEGIN TRAN;

    UPDATE dbo.Bestellungen SET Status = 'Verarbeitung' WHERE BestellungID = 100;

    — Hält X-Lock auf Bestellungen Zeile 100

    — Jetzt: versucht Lock auf Lagerbestand zu bekommen

    UPDATE dbo.Lagerbestand SET Menge = Menge – 1 WHERE ArtikelID = 42;

    — WARTET — weil Session 56 schon X-Lock auf Lagerbestand hält

    COMMIT;

     

    — Gleichzeitig, Transaktion B (Session 56):

    BEGIN TRAN;

    UPDATE dbo.Lagerbestand SET Menge = Menge – 1 WHERE ArtikelID = 42;

    — Hält X-Lock auf Lagerbestand Zeile 42

    — Jetzt: versucht Lock auf Bestellungen zu bekommen

    UPDATE dbo.Bestellungen SET Status = 'Verarbeitung' WHERE BestellungID = 100;

    — WARTET — weil Session 55 schon X-Lock auf Bestellungen hält

    COMMIT;

     

    — Ergebnis: Zirkuläres Warten — Session 55 wartet auf 56, Session 56 wartet auf 55

    — SQL Server wählt ein Victim (typisch: Session 56) und rollt zurück

    — Session 56 bekommt Error 1205, Session 55 kann weiterarbeiten

    Das ist das Lehrbuchbeispiel. Im echten Leben sind Deadlocks oft verschachtelter — mehrere Tabellen, mehrere Indizes, Row-Lock vs. Table-Lock — aber das Grundprinzip ist immer dasselbe: zirkuläres Warten durch unterschiedliche Zugriffsreihenfolge.

    Victim-Auswahl: Wer wird geopfert?

    SQL Server wählt das Victim nach Rollback-Kosten: Die Transaktion mit weniger Log-Einträgen (= weniger zu rückzunehmende Arbeit) wird geopfert. Du kannst das beeinflussen:

    — DEADLOCK_PRIORITY steuert wer als Victim gewählt wird

    — Standard: NORMAL (= 0)

    — Range: LOW (-5) bis HIGH (5), oder als Namen: LOW / NORMAL / HIGH

     

    — "Ich will lieber Victim sein als die andere Session"

    SET DEADLOCK_PRIORITY LOW;

     

    — "Ich will auf keinen Fall Victim sein" (Vorsicht: macht andere wahrscheinlicher zum Victim)

    SET DEADLOCK_PRIORITY HIGH;

     

    — Praktischer Einsatz: In kritischen Transaktionen (z.B. Monats-Abschluss)

    — die auf keinen Fall unterbrochen werden sollen:

    SET DEADLOCK_PRIORITY HIGH;

    BEGIN TRAN;

    — kritische Buchungslogik …

    COMMIT;

    In der Applikation muss Error 1205 immer abgefangen und mit einem Retry behandelt werden — das ist kein Fehler der den Prozess beendet, sondern ein Signal: "Diese Transaktion wurde geopfert — bitte nochmal versuchen." Eine robuste Applikation hat eine Retry-Logik für Deadlock-Victims.

    Deadlock-Graph analysieren: Was SQL Server aufzeichnet

    SQL Server zeichnet jeden Deadlock als XML-Grafik auf. Dieser "Deadlock Graph" ist das mächtigste Analyse-Instrument — er zeigt genau welche Sessions, Objekte, Locks und Statements beteiligt waren.

    Deadlock-Graph aus der System Health Session

    Seit SQL Server 2008 läuft die System Health Extended Events Session automatisch im Hintergrund und zeichnet Deadlocks auf. Keine Konfiguration nötig.

    — Deadlock-Graphen aus System Health Session extrahieren

    — Liefert die letzten Deadlocks als XML

    SELECT

    xdr.value('(@timestamp)[1]', 'datetime2') AS deadlock_zeitpunkt,

    xdr.query('.') AS deadlock_graph_xml

    FROM (

    — System Health Session Daten aus Ring Buffer Target laden

    SELECT CAST(target_data AS XML) AS target_data

    FROM sys.dm_xe_session_targets t

    JOIN sys.dm_xe_sessions s ON t.event_session_address = s.address

    WHERE s.name = 'system_health'

    AND t.target_name = 'ring_buffer'

    ) AS data

    CROSS APPLY target_data.nodes('//RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)

    ORDER BY deadlock_zeitpunkt DESC;

    Das Ergebnis ist ein XML-Dokument das du in SSMS direkt anklicken kannst — SSMS zeigt den Deadlock Graph dann grafisch als Diagramm an. Alternativ kannst du den XML-Inhalt in eine .xdl-Datei speichern und in SSMS öffnen.

    Den Deadlock-Graph lesen

    Der Deadlock Graph besteht aus zwei Typen von Knoten:

  • Process Nodes (blau in SSMS): Jede beteiligte Session — mit Session-ID, Login, aktuellem Statement und Client-Information
  • Resource Nodes (grau/gelb): Das Lock-Objekt um das es geht — Tabelle, Index, Page-ID, Row-ID, Schlüsselwert
  • Die Verbindungslinien zeigen die Lock-Beziehungen: Ein Pfeil von Process zu Resource bedeutet "wartet auf", ein Pfeil von Resource zu Process bedeutet "wird gehalten von". Der Zyklus im Graphen ist der Deadlock. Das Victim ist mit einem "X" markiert.

    Was du im Deadlock Graph suchen sollst:

  • Welche Tabellen/Indizes sind beteiligt? → Indexe als Lösung prüfen
  • In welcher Reihenfolge wurden die Locks genommen? → Zugriffsreihenfolge vereinheitlichen
  • Welche Statements waren beteiligt? → Stored Procedures oder ORM-Code prüfen
  • Handelt es sich um ein Read/Write-Deadlock? → RCSI als Lösung prüfen
  • Deadlocks mit eigener XE-Session überwachen

    Für proaktives Deadlock-Monitoring empfiehlt sich eine eigene XE-Session mit Ring Buffer Target. Damit kannst du Deadlocks in Echtzeit abfragen, ohne auf das Error Log angewiesen zu sein:

    — Eigene Extended Events Session für Deadlock-Monitoring

    — Verweis: Kapitel 08 für XE-Grundlagen und weitere Session-Vorlagen

    CREATE EVENT SESSION [Deadlock_Monitor] ON SERVER

    ADD EVENT sqlserver.xml_deadlock_report (

    ACTION (

    sqlserver.client_app_name, — welche Applikation ist beteiligt?

    sqlserver.client_hostname, — von welchem Host?

    sqlserver.database_name, — in welcher Datenbank?

    sqlserver.username

    )

    )

    ADD TARGET package0.ring_buffer ( — im Speicher halten, keine Datei nötig

    SET max_memory = 51200 — 50 MB Ring Buffer

    );

     

    — Session starten:

    ALTER EVENT SESSION [Deadlock_Monitor] ON SERVER STATE = START;

     

    — Session anhalten (z.B. nach Diagnose):

    — ALTER EVENT SESSION [Deadlock_Monitor] ON SERVER STATE = STOP;

     

    — Aus Ring Buffer lesen (identisch mit System Health Abfrage oben):

    SELECT

    xdr.value('(@timestamp)[1]', 'datetime2') AS zeitpunkt,

    xdr.query('.') AS graph_xml

    FROM (

    SELECT CAST(t.target_data AS XML) AS data

    FROM sys.dm_xe_session_targets t

    JOIN sys.dm_xe_sessions s ON t.event_session_address = s.address

    WHERE s.name = 'Deadlock_Monitor' AND t.target_name = 'ring_buffer'

    ) d

    CROSS APPLY d.data.nodes('//RingBufferTarget/event[@name="xml_deadlock_report"]')

    AS events(xdr)

    ORDER BY zeitpunkt DESC;

    Deadlock-Prävention: Wer an der Ursache arbeitet, löscht das Feuer

    Deadlocks lassen sich vollständig eliminieren — nicht durch Monitoring, sondern durch Prävention. Die Methoden in absteigender Wirksamkeit:

    Regel 1: Tabellen immer in gleicher Reihenfolge zugreifen

    Die wichtigste Anti-Deadlock-Regel überhaupt. Wenn alle Transaktionen im System Tabelle A immer vor Tabelle B sperren, ist ein Deadlock zwischen diesen beiden Tabellen mathematisch unmöglich. Das klingt simpel — ist es auch. Die Herausforderung ist Disziplin im Applikationscode und die Durchsetzung in einem Team. Dokumentiere die Zugriffsreihenfolge als Architekturentscheidung.

    Regel 2: RCSI eliminiert Read/Write-Deadlocks vollständig

    Der häufigste Deadlock-Typ in OLTP-Systemen ist der Read/Write-Deadlock: Session A hat einen X-Lock (schreibt), Session B will einen S-Lock (liest) auf dieselbe Ressource, hat aber schon einen X-Lock auf etwas anderem — auf das A wartet. Mit RCSI braucht Session B keinen S-Lock mehr — sie liest aus dem Versionsstore. Der Zyklus bricht auf. Deadlock weg. Für viele Teams ist RCSI die einzige Maßnahme die sie brauchen.

    Regel 3: UPDLOCK-Hint für U→X-Deadlocks

    Ein häufiges Muster: Zwei Sessions lesen dieselbe Zeile mit S-Lock (READ), wollen dann beide updaten (X). Session A und B halten je einen S-Lock und beantragen gleichzeitig den U-Lock — der U-Lock ist mit S kompatibel, also bekommen beide den U-Lock. Dann wollen beide zu X — X ist nicht kompatibel mit U. Deadlock.

    — UPDLOCK-Hint: Beim Lesen schon den Update Lock nehmen

    — Verhindert das S → U → X Eskalations-Deadlock-Muster

    — Wer den UPDLOCK hat, kann immer zu X upgraden ohne Deadlock

     

    — Statt:

    SELECT * FROM dbo.Bestellungen WHERE BestellungID = @id;

    — … Logik …

    UPDATE dbo.Bestellungen SET Status = 'Verarbeitung' WHERE BestellungID = @id;

     

    — Besser (liest und reserviert gleichzeitig):

    SELECT * FROM dbo.Bestellungen WITH (UPDLOCK)

    WHERE BestellungID = @id;

    — Jetzt hält diese Session U-Lock — die andere Session muss warten

    — Kein Deadlock mehr, weil nur einer U-Lock bekommen kann

    UPDATE dbo.Bestellungen SET Status = 'Verarbeitung' WHERE BestellungID = @id;

    Regel 4: Kurze Transaktionen minimieren Konflikt-Fenster

    Je kürzer eine Transaktion, desto kleiner das Zeitfenster in dem ein Deadlock entstehen kann. Eine Transaktion die 10 ms dauert hat ein 100× kleineres Konflikt-Fenster als eine die 1 Sekunde läuft. Schreiboperationen so spät wie möglich in die Transaktion legen — erst lesen und aufbereiten, dann committen.

    Regel 5: Indizes reduzieren Lock-Granularität

    Fehlende Indizes zwingen SQL Server zu Table Scans — das bedeutet mehr Seiten gesperrt, höhere Eskalationswahrscheinlichkeit, größere Lock-Konfrontationsfläche. Ein covering Index auf die richtigen Spalten reduziert den Scan auf einen Single-Row-Lookup — und damit auf einen einzigen Row Lock. Index-Strategie ausführlich in Kapitel 17.

    Isolation Levels im Blocking-Kontext

    Isolation Levels steuern, wie aggressiv SQL Server Locks setzt und was Transaktionen voneinander sehen dürfen. Sie sind direkt mit Blocking-Verhalten verknüpft. Die vollständige Behandlung aller fünf Levels mit ihren Konsistenz-Garantien folgt in Kapitel 27. Hier der Blocking-Fokus:

     

    Isolation Level

    Leser blockiert Schreiber?

    Schreiber blockiert Leser?

    Dirty Read möglich?

    Deadlock-Risiko

    READ UNCOMMITTED (NOLOCK)

    Nein

    Nein

    Ja — gefährlich

    Gering

    READ COMMITTED (Standard)

    Nein

    Ja

    Nein

    Mittel

    READ COMMITTED SNAPSHOT (RCSI)

    Nein

    Nein

    Nein

    Gering

    REPEATABLE READ

    Ja

    Ja

    Nein

    Hoch

    SERIALIZABLE

    Ja (Range Locks)

    Ja

    Nein

    Sehr hoch

    SNAPSHOT

    Nein

    Nein

    Nein

    Sehr gering

    Tabelle 14.6: Isolation Levels im Blocking-Kontext

     

    READ COMMITTED ist der Standard in SQL Server und ein guter Kompromiss. Aber: Schreiber blockieren Leser. Für viele OLTP-Systeme ist das akzeptabel, für leseintensive Workloads mit häufigen Updates (z.B. Dashboard-Abfragen während des Tagesgeschäfts) kann RCSI die Lösung sein. SERIALIZABLE maximiert die Konsistenz aber auch das Deadlock-Risiko — in der Praxis selten sinnvoll außer für kritische Finanz-Transaktionen.

     

    Tipp: RCSI ist für die meisten OLTP-Systeme die beste Wahl

    Aktiviere RCSI proaktiv auf neuen Datenbanken, bevor die erste Beschwerde über Blocking kommt. Der Performance-Overhead durch TempDB-Versioning ist bei normalen Workloads minimal. Der Gewinn — keine Read/Write-Deadlocks mehr — ist erheblich. Azure SQL Database hat RCSI standardmäßig aktiviert. Das ist kein Zufall.

     

    Fallstudie: Musterwerk GmbH — Blocking durch fehlenden FK-Index

    MWSQL01, die SQL Server Instanz der Musterwerk GmbH (Kapitel 32), zeigt ein klassisches Blocking-Muster: Der Support meldet sporadische Hänger im Auftragssystem, immer zwischen 14:00 und 15:00 Uhr.

    Die Diagnose-Query zeigt eine Blocking-Kette mit bis zu sieben Sessions. Head Blocker ist immer eine ähnliche UPDATE-Anweisung auf die Tabelle AuftragPositionen. Der Wait Type: LCK_M_S. Die blockierten Sessions machen harmlose SELECTs auf die Tabelle Auftraege.

    sys.dm_tran_locks zeigt es: Der Head Blocker hält keinen Row Lock — sondern einen TABLE Lock. Lock Escalation. Das UPDATE auf AuftragPositionen scannt die gesamte Tabelle, weil der Index auf der FK-Spalte AuftragID fehlt. 50.000 Row Locks werden zu einem Table Lock eskaliert — und der sperrt auch alle JOINs von Auftraege auf AuftragPositionen für die Dauer des UPDATEs.

    — Diagnose: Missing Index auf FK-Spalte findet sys.dm_db_missing_index_details

    — Zeigt welche Abfragen von einem fehlenden Index profitieren würden

    SELECT

    mid.statement AS tabelle,

    mid.equality_columns, — WHERE x = …

    mid.inequality_columns, — WHERE x > …

    mid.included_columns, — INCLUDE(…) für Covering Index

    migs.unique_compiles,

    migs.user_seeks,

    migs.avg_total_user_cost * migs.user_seeks AS impact_score — höher = wichtiger

    FROM sys.dm_db_missing_index_details AS mid

    JOIN sys.dm_db_missing_index_groups AS mig

    ON mid.index_handle = mig.index_handle

    JOIN sys.dm_db_missing_index_group_stats AS migs

    ON mig.index_group_handle = migs.group_handle

    ORDER BY impact_score DESC;

    Lösung: Ein einfacher nicht-clustered Index auf AuftragPositionen(AuftragID) eliminiert den Table Scan, verhindert die Lock Escalation, und die Blocking-Kette verschwindet. Das UPDATE läuft jetzt in 0,3 Sekunden statt in 12 Sekunden — und sperrt dabei maximal eine Handvoll Zeilen. Kosten: Index-Erstellung in der Mittagspause, 90 Sekunden.

    Diagnose-Kästen

     

    Warnung: Symptome: Blocking und Deadlocks

    Nutzer berichten über "hängende" oder "eingefrorene" Anwendung, meistens zu bestimmten Tageszeiten (Peak-Last) oder nach bestimmten Aktionen.

    In sys.dm_exec_requests: viele Sessions mit status = SUSPENDED und blocking_session_id > 0.

    In sys.dm_os_wait_stats: LCK_M_S, LCK_M_X, LCK_M_U mit signifikantem Anteil an Gesamtwartezeit.

    Im SQL Server Error Log: "Transaction (Process ID X) was deadlocked…" (Error 1205).

    Wait Statistics Dashboard (Kapitel 09): LCK_M_*-Waits über 5% der Gesamtwartezeit sind auffällig.

    Applikationslogs: Timeout-Fehler, SQLException 1205, Connection-Timeouts bei aktiver DB-Verbindung.

     

     

    Tipp: So misst du das: Blocking-Diagnose-Query

    Vollständige Blocking-Kette in einer Query: Welche Session ist Head Blocker?

     

    SELECT r.session_id AS blockiert, r.blocking_session_id AS durch,

    r.wait_type, ROUND(r.wait_time / 1000.0, 1) AS warten_sek,

    LEFT(qt.text, 200) AS statement_blockiert,

    s.login_name, s.host_name, s.program_name

    FROM sys.dm_exec_requests r

    CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) qt

    JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id

    WHERE r.blocking_session_id > 0

    ORDER BY r.wait_time DESC;

     

    Head Blocker = Session die in blocking_session_id auftaucht, aber selbst

    nicht in session_id der gefilterten Ergebnisse vorkommt.

    Für Deadlock-Graphen: System Health XE Session abfragen (Query oben in Kapitel).

     

     

    Hintergrund: Typische Fehlinterpretationen

    "WITH(NOLOCK) löst das Blocking" — Nein. NOLOCK schafft neue Probleme (Dirty Reads, Error 605) ohne das eigentliche Problem zu lösen. RCSI ist die richtige Antwort.

     

    "Deadlocks sind Bugs" — Nein. Deadlocks sind ein architekturelles Signal: Zugriffsreihenfolge auf Ressourcen ist nicht konsistent. Das ist behebbar.

     

    "Hohe LCK_M_S-Waits bedeuten, wir müssen Locking reduzieren" — Oft ist RCSI die Lösung, nicht das Reduzieren von Konsistenzgarantien.

     

    "Der Head Blocker ist das Problem" — Nicht unbedingt. Der Head Blocker tut nur seinen Job (normale Transaktion). Das Problem ist meist das Design: zu lange Transaktion, fehlender Index, falsches Isolation Level.

     

    "SERIALIZABLE ist sicher — also nutzen wir das" — SERIALIZABLE maximiert Locks und damit Deadlock-Wahrscheinlichkeit. Für die meisten OLTP-Workloads ist READ COMMITTED + RCSI die bessere Wahl.

     

     

    Tipp: Erste Gegenmaßnahmen

    1. Blocked Process Threshold aktivieren (sp_configure, Wert 5): Damit siehst du im Monitoring was passiert, bevor der erste Anruf kommt.

     

    2. RCSI aktivieren (ALTER DATABASE … SET READ_COMMITTED_SNAPSHOT ON): Eliminiert Read/Write-Blocking ohne Applikationsänderung. Sofortige Wirkung.

     

    3. Offene Transaktionen identifizieren: Sessions mit status = sleeping und open_transaction_count > 0 in sys.dm_exec_sessions — das sind oft die Head Blocker.

     

    4. Missing Indexes auf FK-Spalten prüfen: sys.dm_db_missing_index_details — ein Index-Hinzufügen kann Lock Escalation sofort verhindern.

     

    5. Deadlock-Monitoring einschalten: System Health Session läuft automatisch, eigene XE Session für Alerting empfohlen.

     

    Zusammenfassung

    Blocking und Deadlocks sind zwei Seiten derselben Medaille: Locking-Mechanismen die zur Konsistenz notwendig sind, aber zur Performance-Bremse werden, wenn sie nicht richtig kontrolliert werden.

    Blocking entsteht, wenn eine Session auf einen Lock wartet, den eine andere hält. Es ist per se kein Fehler — aber unnötige Blocking durch lange Transaktionen, fehlende Indizes und Lock Escalation sind vermeidbare Performance-Probleme. Die Lock Compatibility Matrix erklärt warum X-Locks so gefährlich für die Parallelität sind. Lock Escalation von 5.000 Row Locks auf einen Table Lock ist der Klassiker, den jeder Administrator kennen sollte.

    Deadlocks sind zirkuläres Warten — zwei Sessions blockieren sich gegenseitig. SQL Server löst das automatisch durch Victim-Auswahl, aber Error 1205 muss in der Applikation behandelt werden. Der Deadlock Graph — zugänglich über die System Health Session — ist das wertvollste Diagnose-Instrument.

    Die wichtigsten Präventionsmaßnahmen in der Praxis: Tabellen immer in gleicher Reihenfolge zugreifen, RCSI für Read/Write-Isolation aktivieren, Transaktionen so kurz wie möglich halten, und fehlende Indizes auf FK-Spalten hinzufügen. NOLOCK ist keine Lösung — er tauscht ein Problem gegen ein schlimmeres.

    Musterwerk GmbH hat gezeigt wie ein einziger fehlender Index eine Blocking-Kette produziert, die sich täglich wiederholt — bis man sys.dm_db_missing_index_details befragt und 90 Sekunden investiert.

     

    Hinweis: Querverweise

    Kapitel 04: SQL Server Storage Engine und Lock Manager — Architekturhintergrund

    Kapitel 08: Extended Events — XE Sessions für Deadlock-Monitoring bauen

    Kapitel 09: Wait Statistics — LCK_M_*-Waits im Gesamtkontext einordnen

    Kapitel 17: Index-Strategie — fehlende Indizes als Blocking-Ursache beseitigen

    Kapitel 27: Transaktionsisolation — alle fünf Isolation Levels in der Tiefe

    Kapitel 28: Locking aus Entwicklersicht — UPDLOCK, HOLDLOCK, Transaktionsdesign

    Kapitel 29: Row Versioning und Snapshot Isolation — RCSI und SNAPSHOT in der Tiefe

    Kapitel 32: Fallstudie Musterwerk GmbH — das FK-Index-Blocking-Problem im Detail

    Kapitel 33: Fallstudie Sparfuchs — Extrembeispiel mit Index-Fragmentierung 97%

     

    Ausblick: Kapitel 15 — Query Performance & Ausführungspläne

    Wir haben gesehen wie Locks entstehen und was sie mit der Performance machen. Aber warum führt SQL Server überhaupt bestimmte Locking-Strategien für bestimmte Abfragen durch? Das hat mit dem Ausführungsplan zu tun: Wie SQL Server entscheidet, ob er einen Index Seek, einen Index Scan oder einen Table Scan macht — und wie diese Entscheidung mit Parallelismus, Join-Strategien und Ressourcenverbrauch zusammenhängt.

    Kapitel 15 öffnet die Blackbox des Query Optimizers. Du lernst Ausführungspläne zu lesen wie ein Pro — nicht nur "welcher Operator", sondern "warum dieser Operator, was hat SQL Server sich dabei gedacht, und wo liegt der Fehler". Wer Blocking verstanden hat und Ausführungspläne lesen kann, hat die wichtigsten Werkzeuge der SQL Server Performance-Analyse in der Hand.

     

    Abb. 1: Deadlock-Entstehung

     

    Abb. 2: Blocking Chain

     

    Kapitel 15

    Weitere Beiträge zum Thema

    Azure SQL für IT-Entscheider

    1. Management Summary Azure SQL bezeichnet eine Familie von Microsofts Cloud-Datenbankdiensten, die SQL Server-Technologie in Azure als Service bereitstellen. Dazu gehören Azure SQL Database (ein einzeldatenbankbasierter PaaS-Dienst für moderne Anwendungen), Azure SQL...

    mehr lesen

    Azure SQL für Entwickler

    Management Summary Azure SQL (PaaS) bietet Softwareentwicklern eine fully-managed SQL-Plattform in der Cloud – mit integrierter Hochverfügbarkeit, automatischen Backups und einfacher Skalierbarkeit. Im Vergleich zu einer selbstverwalteten SQL Server-Instanz entfallen...

    mehr lesen

    Wartungspläne für Microsoft SQL Server

    Management Summary Wartung sichert Verfügbarkeit und Datenintegrität: Geplante Wartungsarbeiten in SQL Server zielen darauf ab, die Verfügbarkeit von Datenbanken hoch zu halten und Datenintegrität zu gewährleisten. Sie minimieren Ausfallzeiten und Risiken und...

    mehr lesen

    SQL Server Monitoring / Überwachung

    Das Monitoring von SQL Server ist entscheidend, um die Leistung und Stabilität Ihrer Datenbank zu gewährleisten. Durch kontinuierliche Überwachung können potenzielle Probleme frühzeitig erkannt und behoben werden, bevor sie sich negativ auf Ihre Anwendungen auswirken....

    mehr lesen

    Microsoft SQL Server Lizenzierung

    Die Lizenzierung von SQL Server kann komplex und kostspielig sein. Eine optimierte Lizenzierungsstrategie kann jedoch erhebliche Kosteneinsparungen und eine effizientere Nutzung der Ressourcen ermöglichen. Als erfahrener Berater werde ich die wichtigsten Schritte und...

    mehr lesen

    Microsoft SQL Server Kostenoptimierung

    Die Verwaltung und Optimierung der Kosten einer SQL Server-Umgebung ist entscheidend für die Effizienz und Rentabilität eines Unternehmens. Als erfahrener Berater weiß ich, dass eine gut durchdachte Strategie zur Kostenoptimierung verschiedene Aspekte der SQL...

    mehr lesen

    SQL Server Analysis Services (SSAS)

    SQL Server Analysis Services (SSAS) ist ein leistungsstarkes analytisches Datenbankmodul, das für Entscheidungsunterstützung und Geschäftsanalysen verwendet wird. Als erfahrener Berater weiß ich, dass SSAS eine Schlüsselrolle bei der Bereitstellung von...

    mehr lesen

    Microsoft SQL Server Sicherheit

    Die Sicherheit von Microsoft SQL Server ist von entscheidender Bedeutung, um die Integrität, Vertraulichkeit und Verfügbarkeit Ihrer Daten zu gewährleisten. Als erfahrener Berater weiß ich, dass eine umfassende Sicherheitsstrategie verschiedene Ebenen und Methoden...

    mehr lesen

    Hochverfügbarkeit für Microsoft SQL Server

    Die Gewährleistung der Hochverfügbarkeit (HA) von Microsoft SQL Server ist entscheidend für die Geschäftskontinuität und die Minimierung von Ausfallzeiten. Als erfahrener Berater weiß ich, dass eine gut durchdachte HA-Strategie verschiedene Technologien und Best...

    mehr lesen

    Indexoptimierung Microsoft SQL Server

    Die Indexoptimierung ist ein zentraler Bestandteil der Leistungssteigerung eines SQL Servers. Als erfahrener Berater weiß ich, dass eine gut durchdachte Indexstrategie entscheidend für die Effizienz und Geschwindigkeit von Datenbankabfragen ist. In diesem Beitrag...

    mehr lesen

    Optimierung Microsoft SQL Server

    Die Optimierung eines SQL Servers ist ein komplexer Prozess, der verschiedene Aspekte der Datenbankleistung berücksichtigt. Ich beschreibe hier die wichtigsten Schritte und Methoden zur Optimierung eines SQL Servers.: Die Optimierung eines SQL Servers ist...

    mehr lesen