Was sind meine Sperroptionen für eine Merge-Anweisung?

12

Ich habe eine gespeicherte Prozedur, die eine MERGEAnweisung ausführt .

Es scheint, als würde beim Durchführen der Zusammenführung standardmäßig die gesamte Tabelle gesperrt.

Ich rufe diese gespeicherte Prozedur innerhalb einer Transaktion auf, in der ich auch einige andere Dinge mache, und ich wünschte, sie würde nur die betroffenen Zeilen sperren.

Ich versuchte es mit dem Hinweis MERGE INTO myTable WITH (READPAST)und es schien weniger zu sperren. Im ms-Dokument wurde jedoch eine Warnung angezeigt, die besagt, dass doppelte Schlüssel eingefügt werden können, wobei sogar der Primärschlüssel umgangen wird.

Hier ist mein Tabellenschema:

CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'WANG')
INSERT INTO StudentDetails
VALUES(2,'JOHNSON')
GO

CREATE TABLE StudentTotalMarks
(
Id INT IDENTITY PRIMARY KEY,
StudentID INTEGER REFERENCES StudentDetails,
StudentMarks INTEGER
)
GO
INSERT INTO StudentTotalMarks
VALUES(1,230)
INSERT INTO StudentTotalMarks
VALUES(2,255)
GO

Hier ist meine gespeicherte Prozedur:

CREATE PROCEDURE MergeTest 
    @StudentId int,
    @Mark int
AS  

WITH Params
AS
(
    SELECT @StudentId as StudentId,
        @Mark as Mark
)
    MERGE StudentTotalMarks AS stm
    USING Params p
    ON stm.StudentID = p.StudentId
    WHEN MATCHED AND stm.StudentMarks > 250 THEN DELETE
    WHEN MATCHED THEN UPDATE SET stm.StudentMarks = p.Mark
    WHEN NOT MATCHED THEN
        INSERT(StudentID,StudentMarks)
        VALUES(p.StudentId, p.Mark);
GO

So beobachte ich die Verriegelung:

begin tran
EXEC MergeTest 1, 1

Und dann in einer anderen Sitzung:

EXEC MergeTest 2, 2

Die zweite Sitzung wartet, bis die erste abgeschlossen ist, bevor Sie fortfahren.

John Buchanan
quelle
1
WITH (READPAST)Weist SQL Server an, nur Zeilen zu überspringen, die von anderen Sitzungen gesperrt wurden. Bist du sicher, dass du das machen willst? Wie viele Zeilen in dieser Tabelle ändern Sie? Zeigen Sie uns das Tabellenschema (einschließlich Indizes) und die MERGEAnweisung, die Sie ausführen.
Nick Chammas
@ NickChammas danke für die Hilfe, ich habe die Frage mit den Details aktualisiert. Ich stelle mir vor, READPAST wäre schlecht ...
John Buchanan

Antworten:

11

Sie müssen dem Abfrageprozessor einen effizienteren Zugriffspfad zum Auffinden von StudentTotalMarksDatensätzen geben. Wie geschrieben, erfordert die Abfrage einen vollständigen Scan der Tabelle mit einem Restprädikat, [StudentID] = [@StudentId]das auf jede Zeile angewendet wird:

Scan-Plan

Die Engine nimmt U(Aktualisierungs-) Sperren beim Lesen als grundlegende Verteidigung gegen eine häufige Ursache von Konvertierungs-Deadlocks. Dieses Verhalten bedeutet, dass die zweite Ausführung blockiert wird, wenn versucht wird, eine USperre für die Zeile zu erhalten, die bereits bei Xder ersten Ausführung mit einer (exklusiven) Sperre gesperrt wurde .

Der folgende Index bietet einen besseren Zugriffspfad, um unnötige USperren zu vermeiden :

CREATE UNIQUE INDEX uq1 
ON dbo.StudentTotalMarks (StudentID) 
INCLUDE (StudentMarks);

Der Abfrageplan enthält jetzt eine Suchoperation für StudentID = [@StudentId], sodass USperren nur für Zielzeilen angefordert werden:

Plan suchen

Der Index wird nicht erforderlich sein , UNIQUEdie Frage auf der Hand zu lösen (obwohl die INCLUDEerforderlich ist, eine Abdeckung Index für diese Abfrage zu machen).

Herstellung StudentIDder PRIMARY KEYvon dem StudentTotalMarksauch das Problem Zugriffspfad (und die scheinbar redundante lösen würde Tabelle Identfernt wird Spalte könnte). Sie sollten alternative Schlüssel immer mit einer UNIQUEoder PRIMARY KEYEinschränkung erzwingen (und vermeiden, bedeutungslose Ersatzschlüssel ohne guten Grund hinzuzufügen).

Paul White 9
quelle