Deadlock-Diagramm mit einer Sperre für einen Index für eine scheinbar nicht verwandte Tabelle

7

Ich habe ein Deadlock-Diagramm von einem Deadlock, bei dem ein Prozess ein SELECT und einer ein UPDATE ausführt. Dies scheint der klassische Fall zu sein, in dem SELECT eine NCI-Sperre erhält, um einen Join durchzuführen, und dann eine CI-Sperre, um alle Daten durch Nachschlagen abzurufen. Das UPDATE verwendet die CI-Sperre, um eine Aktualisierung durchzuführen, und muss dann eine NCI sperren, da die Aktualisierung zu einer Statusänderung führt und die NCI das Auffinden von Elementen nach Status erleichtert.

Das Problem ist, dass sich eine der Sperren, die das UPDATE wünscht, NICHT in der Tabelle befindet, die aktualisiert wird, und ich kann nicht herausfinden, warum dies geschieht.

Hier ist die AUSWAHL:

SELECT *,
       RIGHT(c.CC_NUMBER, 4) AS CC_LAST_4,
       DATEDIFF(ss, '1970-01-01', plan_started ) plan_started_epoch,
       DATEDIFF(ss, '1970-01-01', plan_expires ) plan_expires_epoch
FROM customers c, accounts a, parent_cos pc, htt_customers_overlay_ultra u
WHERE c.customer_id = a.customer_id
AND   u.customer_id = c.customer_id
AND   a.cos_id=pc.cos_id
AND   u.customer_id = 9300;

Hier ist das UPDATE:

UPDATE htt_customers_overlay_ultra SET plan_state = 'Active'  WHERE customer_id = 9300;

Gemäß dem Deadlock-Diagramm erhält das UPDATE jedoch eine Sperre für ACCOUNTS.ACCOUNT0, die PK (CI) der Tabelle ACCOUNTS. Die Overlay-Tabelle enthält keine Fremdschlüssel. Es gibt einige Standardeinschränkungen, für die ich derzeit keine Berechtigung habe.

Ich habe mir das Deadlock-Diagramm in SSMS und in SQL Sentry Plan Explorer Pro angesehen und bin nicht klüger.

Hier sind die Ausführungspläne:

Für die SELECT

Für das UPDATE

Ich möchte herausfinden, warum es diese Sperre erhält, und dann den besten Weg, um diese Anrufe zu serialisieren.

Dinge, die mir bekannt sind und die ich dem Kunden bereits mitgeteilt habe, die sich auf die genommenen Schlösser auswirken, aber nicht erklären, welche scheinbar nicht verwandte Schlösser entstehen:

Entfernen Sie * und identifizieren Sie die benötigten Spalten und ändern Sie die NCIs, um sie abzudecken. Dies würde möglicherweise dazu führen, dass SELECT weniger Sperren verwendet

Stellen Sie fest, warum das System dieselben Daten auswählt, die von einem anderen Prozess verarbeitet werden. Dies würde möglicherweise die beiden Prozesse verringern, die gleichzeitig ausgeführt werden

In SELECT befindet sich ein Tabellenscan

Cade Roux
quelle
Könnte die Aktualisierungsabfrage die XTastensperre für "dbo.ACCOUNTS" von einer früheren Anweisung in derselben Transaktion erhalten haben, die in der Grafik nicht dargestellt ist?
Martin Smith
Wenn ich die Grafik richtig lese, SELECThat Uder PK-Index eine Sperre von htt_customers_overlay_ultra- warum? Für diesen Prozess wird 0 Protokoll verwendet.
Jon Seigel
@ JonSeigel - Nein, das Update ( process589f948) hat eine USperre und versucht, es in eine XSperre umzuwandeln , wird aber durch eine SSperre blockiert , die von SELECT( process5240988) gehalten wird
Martin Smith
@Cade Roux: Angenommen, Martin Smith hat den Schuldigen gefunden, ist es wahrscheinlich am einfachsten, solche Probleme zu aktivieren, um solche Probleme zu vermeiden read_committed_snapshot.
a1ex07
Von skalaren UDFs ausgegebene Auswahlen enthalten zwar Sperren, werden jedoch nicht in Ausführungsplänen angezeigt. Vielleicht löst Ihr Update einen Trigger aus, der eine skalare UDF verwendet?
AK

Antworten:

6

Die UPDATEAbfrage hat eine XSperre für einen Schlüssel in "dbo.ACCOUNTS", die verhindert, SELECTdass eine SSperre abgerufen wird .

Die SELECTAbfrage hat eine SSperre für einen Schlüssel von htt_customers_overlay_ultra. Die UPDATEAbfrage hat eine USperre für denselben Schlüssel und wird beim Versuch, diese in eine XSperre umzuwandeln, blockiert .

Der Ausführungsplan für das ist UPDATEüberhaupt nicht verfügbar, Accountsdaher gibt es keinen offensichtlichen Grund dafür, dass eine Schlüsselsperre aktiviert ist Accounts. Die Update-Transaktion startet 0.01Sekunden vor dem Batch. 2013-01-13 08:49:30.213vs 2013-01-13 08:49:30.223.

Möglicherweise gab es eine vorhergehende Anweisung in einem anderen Stapel (daher im Deadlock-Diagramm nicht dargestellt), die die Transaktion tatsächlich gestartet und die mysteriöse XSperre erworben hat.

Martin Smith
quelle
Ich glaube, der gesamte Code besteht aus impliziten Transaktionen in einzelnen Ad-hoc-Stapeln, die von PHP generiert wurden. Ich denke, es muss eine andere Einschränkung geben, aber ich sehe keine Fremdschlüssel. Es gibt einige Standardeinschränkungen, für die ich versuche, die Definitionen zu erhalten,
Cade Roux
@CadeRoux - Wie kann die Transaktion dann vor dem Batch beginnen? Wenn das UPDATEto htt_customers_overlay_ultrazuvor Accountsin derselben Transaktion aktualisiert worden wäre, würde es dies natürlich erklären (obwohl es ein nicht aktualisierendes Update sein müsste, da das verwendete Protokoll = 0 ist) oder möglicherweise ein SELECTmit einem expliziten XLOCKHinweis.
Martin Smith
Ich glaube nicht, dass sie irgendwelche Transaktionen ausführen - ich denke, dass diese beiden Abfragen gleichzeitig von verschiedenen Teilen der App ausgelöst wurden (was seltsam erscheint, da beide auf ein einziges Konto beschränkt sind - oder dass mehrere Komponenten derselben Seite asynchron geladen werden mehrere Anfragen) und sie hatten das Pech (oder vielleicht ist es üblich, dass der Beitrag der Änderung gleichzeitig mit dem Laden von Daten auf dem Konto für einen anderen Teil der Seite ausgeführt wird), um einen Deadlock zu verursachen.
Cade Roux
2
@ Martin Smith: Ihre Erklärung erscheint mir sehr logisch. Eine weitere Sache, die wahrscheinlich Ihre Antwort beweist - im Speicherauszug für die zweite Abfrage (Update) trancount="2". Ich glaube, es bedeutet, dass es 2 gab begin transaction... Das kann wiederum erklären, warum Dump nicht hat update accounts...
a1ex07
@ a1ex07 - Gut entdeckt. Wenn @@trancount = 2es begin tranirgendwo explizit AFAIK geben muss .
Martin Smith