Ich habe eine gespeicherte Prozedur, die eine MERGE
Anweisung 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.
quelle
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 dieMERGE
Anweisung, die Sie ausführen.Antworten:
Sie müssen dem Abfrageprozessor einen effizienteren Zugriffspfad zum Auffinden von
StudentTotalMarks
Datensä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: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, eineU
Sperre für die Zeile zu erhalten, die bereits beiX
der ersten Ausführung mit einer (exklusiven) Sperre gesperrt wurde .Der folgende Index bietet einen besseren Zugriffspfad, um unnötige
U
Sperren zu vermeiden :Der Abfrageplan enthält jetzt eine Suchoperation für
StudentID = [@StudentId]
, sodassU
Sperren nur für Zielzeilen angefordert werden:Der Index wird nicht erforderlich sein ,
UNIQUE
die Frage auf der Hand zu lösen (obwohl dieINCLUDE
erforderlich ist, eine Abdeckung Index für diese Abfrage zu machen).Herstellung
StudentID
derPRIMARY KEY
von demStudentTotalMarks
auch das Problem Zugriffspfad (und die scheinbar redundante lösen würde TabelleId
entfernt wird Spalte könnte). Sie sollten alternative Schlüssel immer mit einerUNIQUE
oderPRIMARY KEY
Einschränkung erzwingen (und vermeiden, bedeutungslose Ersatzschlüssel ohne guten Grund hinzuzufügen).quelle