SQL-Server-Timeouts: Abbruch, Bereinigung und Wiederholung
Trennen Sie Verbindungs-, Befehls- und Lock-Timeouts und gestalten Sie Wiederholungen so, dass unklare Antworten keine doppelten Änderungen erzeugen.
Ein Timeout bedeutet, dass ein Aufrufer sein Zeitbudget zum Warten ausgeschöpft hat. Daraus folgt noch nicht, ob SQL langsam oder blockiert war, vor dem Commit abgebrochen wurde oder bereits erfolgreich schrieb und nur die Antwort verloren ging. Eine sofortige Wiederholung kann deshalb aus einer Verzögerung doppelte Geschäftsoperationen machen.
Das abgelaufene Zeitbudget bestimmen
Ein Verbindungs-Timeout betrifft den Aufbau der Verbindung, einschließlich Netzwerk, Anmeldung oder Ressourcenbeschaffung. Ein Befehls-Timeout betrifft die Ausführung über den Clienttreiber. SET LOCK_TIMEOUT begrenzt dagegen das Warten auf Sperren innerhalb von SQL Server. Diese Einstellungen gelten für verschiedene Phasen und sind nicht austauschbar.
Das Beispiel ändert nur die Sperrwartezeit der aktuellen Sitzung und setzt anschließend den unbegrenzten Standardwert zurück. Es begrenzt nicht die gesamte Abfragedauer.
SET LOCK_TIMEOUT 1500;
SELECT @@LOCK_TIMEOUT AS LockTimeoutMilliseconds;
SET LOCK_TIMEOUT -1;
SELECT XACT_STATE() AS TransactionState,
@@TRANCOUNT AS TransactionCount;
Ein Lock-Timeout erzeugt einen klassifizierbaren SQL-Server-Fehler. Ein Befehls-Timeout wird typischerweise vom Treiber gemeldet und löst eine Abbruchanforderung aus. Protokollieren Sie Treiber, Fehlerdetails, Dauer, Korrelationskennung und den Zustand einer eventuell aktiven Transaktion. Die allgemeine Fehlermeldung eines Webframeworks reicht zur Ursachenbestimmung nicht.
Unterscheiden Sie auch die HTTP-Frist vom Datenbankbudget. Beendet die Webschicht eine Anfrage, ohne den Abbruch weiterzugeben, kann die Datenbank weiterarbeiten. Planen Sie Zeit für Bereinigung und eine brauchbare Antwort ein, statt alle Grenzen auf denselben Wert zu setzen.
Den laufenden Zustand erfassen
Sichern Sie während des Vorfalls Warteart, Blockierung, Laufzeit und offene Transaktionen. Diese Leseabfragen benötigen versionsabhängige Diagnoserechte für die serverweite Sicht.
SELECT
session_id, request_id, status, command,
wait_type, wait_time, blocking_session_id,
total_elapsed_time, cpu_time,
reads, logical_reads, writes
FROM sys.dm_exec_requests
WHERE session_id <> @@SPID;
SELECT
session_id, status, open_transaction_count,
last_request_start_time, last_request_end_time,
host_name, program_name
FROM sys.dm_exec_sessions
WHERE is_user_process = 1
AND open_transaction_count > 0;
Ein auf Sperren wartender Request erfordert eine andere Untersuchung als eine CPU-intensive Abfrage oder eine Anforderung, die auf Arbeitsspeicher wartet. Die zweite Abfrage findet auch schlafende Sitzungen mit offenen Transaktionen. Diese fehlen möglicherweise in einer Liste aktiver Requests. Host- und Programmnamen sind vom Client gelieferte Diagnoseangaben, keine vertrauenswürdigen Identitäten.
Bei wiederkehrenden Fällen verbinden Sie Anwendungszeiten mit einer gezielten Extended-Events-Erfassung von Attention und passenden Abschluss- oder Fehlerereignissen. Attention zeigt eine Abbruchanforderung des Clients. Daraus ergibt sich jedoch nicht, ob ein Benutzer, ein Zeitlimit oder ein Clientproblem der Auslöser war.
Ein Abbruch garantiert nicht, dass jede explizite Transaktion vollständig zurückgerollt wurde. Die Anwendung muss ihren Transaktionslebenszyklus verwalten. Nach einem Fehler soll sie ihre eigene Transaktion nach Möglichkeit abbrechen, Fehler bei der Bereinigung behandeln und eine Verbindung mit unklarem Zustand verwerfen. Verlassen Sie sich nicht ausschließlich auf T-SQL-CATCH: Client-Attention verhält sich nicht wie jeder gewöhnliche SQL-Fehler.
Ebenso wenig darf Bibliothekscode ohne Vertrag die Transaktion eines übergeordneten Aufrufers zurückrollen. Legen Sie fest, wer Arbeit beginnt, bestätigt und verwirft. Diese Zuständigkeit beeinflusst die Zuverlässigkeit stärker als ein einzelner Timeout-Wert.
Wiederholungen mit stabiler Identität absichern
Angenommen, eine zahlungsähnliche Operation wurde bestätigt, aber die Antwort ging verloren. Eine Wiederholung mit neuer Identität kann denselben Vorgang erneut schreiben. Geben Sie dem Geschäftsbefehl einen stabilen Idempotenzschlüssel und erzwingen Sie dessen Eindeutigkeit in der Datenbank. Speichern Sie das Ergebnis, damit derselbe Schlüssel den bestehenden Ausgang zurückliefert.
Schlüssel und fachliche Änderung müssen gemeinsam committen. Zwei getrennte Transaktionen können einen gespeicherten Schlüssel ohne ausgeführte Operation hinterlassen. Kommt derselbe Schlüssel mit anderem Inhalt erneut, weisen Sie den Widerspruch zurück.
Verwenden Sie begrenzte Wiederholungen mit Warteabstand nur für ausdrücklich wiederholbare Fehler. Zusätzliche Anfragen lösen keine lange Blockierungskette. Bei unbekanntem Commit-Status muss zunächst der vorhandene Ausgang geklärt werden. Testen Sie Abbruch während Ausführung, beim Warten auf Sperren und nach Commit mit verlorener Antwort.
Ein höheres Limit kann für einen bewusst langen Export passen. Prüfen Sie trotzdem dessen Ressourcenbindung und die Folgen für interaktive Anfragen. Entscheidend sind eine nachvollziehbare Frist und ein geklärter Transaktionsausgang.
Technische Referenzen: Microsoft Learn: Query timeout troubleshooting · Microsoft Learn: SET LOCK_TIMEOUT · Microsoft Learn: XACT_STATE.