J'ai une procédure stockée qui exécute une MERGE
instruction .
Il semble qu'il verrouille la table entière par défaut lors de la fusion.
J'appelle cette procédure stockée à l'intérieur d'une transaction où je fais également d'autres choses et je souhaite que cela ne verrouille que les lignes affectées.
J'ai essayé l'indice MERGE INTO myTable WITH (READPAST)
et il semblait se verrouiller moins. Mais il y avait un avertissement dans le ms doc qui disait qu'il pouvait insérer des clés en double, contournant même la clé primaire.
Voici mon schéma de table:
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
Voici ma procédure stockée:
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
Voici comment j'observe le verrouillage:
begin tran
EXEC MergeTest 1, 1
Et puis dans une autre session:
EXEC MergeTest 2, 2
La deuxième session attend la fin de la première avant de continuer.
sql-server
sql-server-2008
merge
John Buchanan
la source
la source
WITH (READPAST)
indique à SQL Server d'ignorer simplement les lignes verrouillées par d'autres sessions. Êtes-vous sûr de vouloir faire ça? De plus, combien de lignes de ce tableau modifiez-vous? Montrez-nous le schéma de la table (y compris les index) et l'MERGE
instruction que vous exécutez.Réponses:
Vous devez donner au processeur de requêtes un chemin d'accès plus efficace pour localiser les
StudentTotalMarks
enregistrements. Comme écrit, la requête nécessite une analyse complète de la table avec un prédicat résiduel[StudentID] = [@StudentId]
appliqué à chaque ligne:Le moteur prend
U
(met à jour) les verrous lors de la lecture comme défense de base contre une cause courante de blocages de conversion. Ce comportement signifie que les seconds blocs d'exécution lorsque vous essayez d'obtenir unU
verrou sur la ligne déjà verrouillée avec unX
verrou (exclusif) par la première exécution.L'index suivant fournit un meilleur chemin d'accès, évitant de prendre des
U
verrous inutiles :Le plan de requête inclut désormais une opération de recherche
StudentID = [@StudentId]
, lesU
verrous ne sont donc demandés que sur les lignes cibles:Il n'est pas nécessaire que l' index soit
UNIQUE
pour résoudre le problème en question (bien qu'ilINCLUDE
soit nécessaire pour en faire un index de couverture pour cette requête).Faire
StudentID
lePRIMARY KEY
duStudentTotalMarks
tableau résoudrait aussi le problème de chemin d'accès (et apparemment redondantId
pourrait être retiré colonne). Vous devez toujours appliquer des clés alternatives avec une contrainteUNIQUE
ouPRIMARY KEY
(et éviter d'ajouter des clés de substitution sans signification sans raison valable).la source