Tôi có một thủ tục được lưu trữ truy vấn một bảng xếp hàng bận rộn được sử dụng để phân phối công việc trong hệ thống của chúng tôi. Bảng trong câu hỏi có khóa chính trên WorkID và không trùng lặp.
Một phiên bản đơn giản của truy vấn là:
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)
Các #Types
bảng được phổ biến trước đó trong thủ tục.
Như tôi đã nói, WorkTable
đang bận và đôi khi trong khi truy vấn này đang chạy, tôi TẠM một trong các bản ghi đang di chuyển từ một bộ các bộ lọc sang bộ lọc WHERE
khác. Cụ thể, điều này xảy ra khi ai đó bắt đầu làm việc trên một mục và W.InProgress
thay đổi từ 0 thành 1. Khi điều này xảy ra, tôi bị vi phạm khóa trùng lặp khi tôi cố thêm khóa chính vào bảng tạm thời mà truy vấn này đang chèn vào.
Tôi đã xác nhận trong kế hoạch truy vấn được tạo khi xảy ra lỗi không có sự song song, mức cô lập READ COMMITTED
và không có bản ghi trùng lặp trong bảng nguồn. Bạn cũng có thể thấy không có JOIN
cách nào khác để có được các sản phẩm cartesian ở đây.
Đây là kế hoạch truy vấn ẩn danh:
Câu hỏi là, điều gì gây ra sự trùng lặp và làm thế nào tôi có thể dừng nó lại?
Tôi nghĩ READ COMMITTED
nên làm việc ở đây, tôi cần khóa. Tôi gần như tích cực các bản sao xảy ra khi InProgress
bit trên bản ghi thay đổi trong khi tôi truy vấn. Tôi biết điều này bởi vì bảng lưu trữ thời gian của sự thay đổi đó và nó chỉ trong một phần nghìn giây khi tôi truy vấn và gặp lỗi.