Sleeping SPID blockiert andere Transaktionen

16

Ich habe wirklich Probleme beim Aufspüren von Blockierungen.

Der SPID-Status für die Root-Blockierung lautet 'Sleeping', der cmd lautet 'AWAITING COMMAND' und der sqltextist SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Wenn ich den Bericht Top Transactions by Blocked Transactions Count anzeige, lautet die Blocking SQL-Anweisung '-'.

Ich habe eine Ablaufverfolgung für SQL durchgeführt und wenn die Blockierung auftritt, die SPID für die Root-Blockierung verfolgt, aber es hat mich nicht wirklich weitergebracht. Die letzte trace-Anweisung ist dieselbe wie sqltextoben SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Ich habe alle zugehörigen gespeicherten Prozeduren überprüft, um sicherzustellen, dass sie TRY / CATCH BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN-Anweisungen haben (wir verwenden gespeicherte Prozeduren für alles, damit keine eigenständigen Anweisungen ausgeführt werden). Dieses Problem ist in den letzten 24 Stunden aufgetreten und niemand behauptet, Änderungen am System vorgenommen zu haben.

Lösung: Eine unserer selten verwendeten gespeicherten Prozeduren hatte einen Fehler mit einer Einfügung (Anzahl der Spalten stimmte nicht überein), aber wir sind immer noch verwirrt darüber, was genau passiert ist.

Bei der Betrachtung aller Ablaufverfolgungsinformationen wurde die EXEC-Anweisung für diese gespeicherte Prozedur zu bestimmten Zeiten aufgelistet, jedoch NIEMALS, bevor der BLOCK auf der blockierenden SPID auftrat. Es schien, dass der Trace zu Beginn der Blockierung nicht die Ausführung (oder eine der darin enthaltenen Anweisungen) aufzeichnete. Es gibt jedoch auch andere Zeiten, in denen der Trace die Ausführung aufgezeichnet hat und keine Blockierung aufgetreten ist.

Der Fehlerbericht für gespeicherte Prozeduren stammte von einem Benutzer, und ich konnte mehrere EXEC-Anweisungen in Ablaufverfolgungen finden und in SSMS ausführen. Zu keinem Zeitpunkt, als ich sie rannte, traten Blockierungen auf oder hingen sie. Sie wurden wie erwartet ausgeführt (der catch-Block hat die Transaktion nach dem Fehler ausgelöst und zurückgesetzt). Nach dem Beheben der gespeicherten Prozedur ist das Problem nicht mehr aufgetreten.

Brad
quelle
Ich gehe davon aus, dass der Hostname der blockierenden SPID überhaupt nicht geholfen hat.
Jon Seigel
Nein, es ist nur die IP eines unserer Webserver ... Wir haben eine andere Idee, jedes SQL-Login für jeden SPROC-Aufruf während des Anmelde- / Registrierungsprozesses (von dem wir glauben, dass dort der Fehler auftritt) in einen separaten Benutzernamen zu ändern helfen Sie uns zu lokalisieren, welches SPROC die Blockierung verursachen könnte.
Brad
1
TRY / CATCH fängt keine Kompilierungsfehler ab, und eine nicht übereinstimmende Spalteneinfügung wäre ein solcher Kompilierungsfehler. Dies würde auch niemals viele der XX: Completed-Profiler-Ereignisse auslösen.
Remus Rusanu
1
In diesem Fall handelt es sich eigentlich nicht um einen Kompilierungsfehler, da der Genie-Entwickler INSERT INTO [table] SELECT * von [othertable] verwendet hat und es nicht in Peer abgefangen wurde. Ich habe den SPROC on Development 1000-mal von ColdFusion aus in 3 gleichzeitigen Sitzungen ausgeführt und dabei nie eine Transaktion offen gelassen, wie sie in der Produktion war.
Brad

Antworten:

10

Aus Kommentaren geht hervor, dass Sie ein clientseitiges Zeitlimit für Befehle hatten, durch das die SQL-Abfrage abgebrochen wurde. Dadurch wird die Transaktion nicht zurückgesetzt, da die Verbindung auf SQL Server aufgrund von Verbindungspooling geöffnet bleibt.

Sie müssen also SET XACT_ABORT ON verwenden oder einen Client-Rollback-Code hinzufügen

Unter SQL Server-Transaktionszeitlimit finden Sie alle wichtigen Details

gbn
quelle
Alle unsere SPROCs enthalten TRY / CATCH-Blöcke und BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN-Anweisungen, wobei ROLLBACK im CATCH enthalten ist. Wäre XACT_ABORT noch wirksam?
Brad
@ Brad: ja. Siehe meinen Link. Der catch-Block wird auf CommandTimeout
gbn
gbn: Danke. Ich bin immer noch verwirrt. Unsere Verbindungen sind auf Never Timeout (0) eingestellt. Sie sagen also, wenn wir Verbindungen wiederverwenden und eine Verbindung einen SPROC mit einem Fehler ausführt (der TRY / CATCH- und TRAN-Blöcke enthält), kann sie irgendwie niemals den ROLLBACK im CATCH-Block ausführen, wodurch Tabellen gesperrt und eine Transaktion beibehalten werden öffnen? Das ergibt für mich keinen Sinn.
Brad
@Brad: Ein SPROC mit einem Fehler trifft den CATCH-Block. Ich habe nicht anders oder anders gesagt. In meinem Link wird jedoch angegeben, was passiert, wenn Sie ein CommandTimeout haben, das sich von einem ConnectionTimeout unterscheidet. Der Client sagt "Abbruch" und SQL Server beendet die Verarbeitung. Ergo, der CATCH-Block, das Rollback oder das Commit wird nie getroffen
gbn
Ich glaube nicht, dass wir ein CommandTimeout angegeben haben. Alle unsere gespeicherten Prozeduren werden mit SQLstress getestet und müssen bei 10 Benutzern und 10 Iterationen (mindestens) unter 1000 ms ausgeführt werden. Ich bin immer noch sehr verwirrt darüber, was passiert ist, aber ich aktualisiere die Frage mit dem, was wir als Problem herausgefunden haben.
Brad
9

Verwenden Sie das most_recent_sql_handle in sys.dm_exec_connections, um die zuletzt ausgeführte Anweisung anzuzeigen.

SELECT  t.text,
        QUOTENAME(OBJECT_SCHEMA_NAME(t.objectid, t.dbid)) + '.'
        + QUOTENAME(OBJECT_NAME(t.objectid, t.dbid)) proc_name,
        c.connect_time,
        s.last_request_start_time,
        s.last_request_end_time,
        s.status
FROM    sys.dm_exec_connections c
JOIN    sys.dm_exec_sessions s
        ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t
WHERE   c.session_id = 72;--your blocking spid

Überprüfen Sie auch, ob für diese Spid offene Transaktionen vorhanden sind

SELECT  st.transaction_id,
        at.name,
        at.transaction_begin_time,
        at.transaction_state,
        at.transaction_status
FROM    sys.dm_tran_session_transactions st
JOIN    sys.dm_tran_active_transactions at
        ON st.transaction_id = at.transaction_id
WHERE   st.session_id = 72;--your blocking spid
Sebastian Meine
quelle
Sie können auch verwenden DBCC INPUTBUFFER(spid), um die zuletzt ausgeführte SQL anzuzeigen.
Mike Fal
Ich habe all diese verwendet und der letzte Befehl ist immer der, den ich in meinen ursprünglichen Beitrag geschrieben habe: SET TRANSACTION ISOLATION LEVEL READ COMMITTED. Ich habe auch DBCC OPENTRAN ausgeführt und sehe, dass für die blockierende PID eine Transaktion offen ist.
Brad
Meine erste Auswahl gibt Ihnen auch den Prozedurnamen, wenn die Anweisung tatsächlich Teil einer Prozedur ist.
Sebastian Meine
Ich versichere Ihnen, wir verwenden keine Ad-hoc-Abfragen von unseren Webservern. Wenn ich diese erste Abfrage ausführe, erhalte ich auch ohne die WHERE-Klausel den Namen SPROC nur für eine Handvoll SQL-Sitzungen, der Rest dieser Spalte ist NULL.
Brad
Mir ist aufgefallen, dass ich unzählige Sitzungen habe, in denen "SET TRANSACTION ISOLATION LEVEL READ COMMITTED" angezeigt wird und alle von ColdFusion stammen (dem wichtigsten Skript, das auf unseren Webservern verwendet wird). Möglicherweise gibt ColdFusion im Leerlauf diese Anweisung aus, um eine Verbindung offen zu halten (da Verbindungen offen gehalten werden sollen).
Brad
4

Haben Sie versucht, Adam Machanics sp_whoisactive zu verwenden ? Es gibt eine Option, mit der der äußere Befehl überprüft werden kann, ob er tatsächlich in einem Proc enthalten ist. Möglicherweise hält die Anwendung eine Transaktion offen, anstatt sie festzuschreiben. Schauen Sie sich auch DBCC OPENTRAN an.

Eric Humphrey - Lotsahelp
quelle
Vielen Dank für DBCC OPENTRAN. Es sagt mir, dass die blockierende PID eine offene Transaktion hat, aber keine weiteren Details verfügbar sind. sp_whoisactive gibt die gleichen Informationen zum blockierten Prozess zurück, die ich selbst erhalten konnte. Es gibt noch keine Details darüber, was los ist, außer "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"
Brad