J'ai une procédure stockée qui interroge une table de file d'attente occupée qui est utilisée pour distribuer le travail dans notre système. Le tableau en question a une clé primaire sur WorkID et aucun doublon.
Une version simplifiée de la requête est:
INSERT INTO #TempWorkIDs (WorkID)
SELECT
W.WorkID
FROM
dbo.WorkTable W
WHERE
(@bool_param = 0 AND
((W.InProgress = 0
AND ISNULL(W.UserID, -1) != @userid_param
AND (@bool_filtered = 0
OR W.TypeID IN (SELECT TypeID FROM #Types AS t)))
OR
(@bool_param = 1
AND W.InProgress = 1
AND W.UserID != @userid_param)
OR
(@Auto_Param = 0
AND W.UserID = @userid_param)))
OR
(@bool_param = 1 AND W.UserID = @userid_param)
OPTION
(RECOMPILE)
Le #Types
tableau est rempli plus tôt dans la procédure.
Comme je l'ai dit, WorkTable
est occupé, et parfois pendant que cette requête est en cours d'exécution, je SUSPECTE l' un des enregistrements se déplace d'un ensemble de filtres dans WHERE
un autre. Plus précisément, cela se produit lorsque quelqu'un commence à travailler sur un élément et les W.InProgress
modifications de 0 à 1. Lorsque cela se produit, j'obtiens une violation de clé en double lorsque j'essaie d'ajouter une clé primaire à la table temporaire dans laquelle cette requête est insérée.
J'ai confirmé dans le plan de requête généré lorsque l'erreur se produit qu'il n'y a pas de parallélisme, que le niveau d'isolement est READ COMMITTED
et qu'il n'y a pas d'enregistrements en double dans la table source. Vous pouvez également voir qu'il n'y a pas de JOIN
s ou autre moyen d'obtenir des produits cartésiens ici.
Voici le plan de requête anonyme:
La question est, qu'est-ce qui cause les doublons et comment puis-je l'arrêter?
Je pense que READ COMMITTED
devrait fonctionner ici, j'ai besoin de verrouillage. Je suis presque InProgress
certain que les dupes se produisent lorsque le bit sur un enregistrement change pendant que j'interroge. Je le sais car la table stocke l'heure de ce changement et elle se situe en quelques millisecondes lorsque je demande et obtient l'erreur.