Trong một trong các cơ sở dữ liệu của chúng tôi, chúng tôi có một bảng được truy cập đồng thời theo nhiều luồng. Chủ đề cập nhật hoặc chèn hàng qua MERGE
. Thỉnh thoảng cũng có các luồng xóa hàng, vì vậy dữ liệu bảng rất dễ bay hơi. Chủ đề làm uperts đôi khi bị bế tắc. Vấn đề này trông giống như một mô tả trong câu hỏi này . Tuy nhiên, sự khác biệt là trong trường hợp của chúng tôi, mỗi luồng sẽ cập nhật hoặc chèn chính xác một hàng .
Thiết lập đơn giản là sau. Bảng này là đống với hai chỉ mục không bao gồm duy nhất trên
CREATE TABLE [Cache]
(
[UID] uniqueidentifier NOT NULL CONSTRAINT DF_Cache_UID DEFAULT (newid()),
[ItemKey] varchar(200) NOT NULL,
[FileName] nvarchar(255) NOT NULL,
[Expires] datetime2(2) NOT NULL,
CONSTRAINT [PK_Cache] PRIMARY KEY NONCLUSTERED ([UID])
)
GO
CREATE UNIQUE INDEX IX_Cache ON [Cache] ([ItemKey]);
GO
và truy vấn điển hình là
DECLARE
@itemKey varchar(200) = 'Item_0F3C43A6A6A14255B2EA977EA730EDF2',
@fileName nvarchar(255) = 'File_0F3C43A6A6A14255B2EA977EA730EDF2.dat';
MERGE INTO [Cache] WITH (HOLDLOCK) T
USING (
VALUES (@itemKey, @fileName, dateadd(minute, 10, sysdatetime()))
) S(ItemKey, FileName, Expires)
ON T.ItemKey = S.ItemKey
WHEN MATCHED THEN
UPDATE
SET
T.FileName = S.FileName,
T.Expires = S.Expires
WHEN NOT MATCHED THEN
INSERT (ItemKey, FileName, Expires)
VALUES (S.ItemKey, S.FileName, S.Expires)
OUTPUT deleted.FileName;
tức là, kết hợp xảy ra bởi khóa chỉ mục duy nhất. Gợi ý HOLDLOCK
ở đây, vì đồng thời (như được khuyên ở đây ).
Tôi đã làm điều tra nhỏ và sau đây là những gì tôi tìm thấy.
Trong hầu hết các trường hợp kế hoạch thực hiện truy vấn là
với mẫu khóa sau
tức là IX
khóa trên đối tượng theo sau là khóa chi tiết hơn.
Tuy nhiên, đôi khi, kế hoạch thực hiện truy vấn là khác nhau
(hình dạng kế hoạch này có thể được ép buộc bằng cách thêm INDEX(0)
gợi ý) và mô hình khóa của nó là
X
khóa thông báo được đặt trên đối tượng sau khi đã IX
được đặt.
Vì hai IX
là tương thích, nhưng hai X
là không, điều xảy ra theo đồng thời là
Bế tắc !
Và đây là phần đầu tiên của câu hỏi phát sinh. Là đặt X
khóa trên đối tượng sau khi IX
đủ điều kiện? Nó không phải là lỗi?
Tài liệu nêu rõ:
Khóa ý định được đặt tên là khóa mục đích vì chúng có được trước khi khóa ở cấp thấp hơn và do đó báo hiệu ý định đặt khóa ở mức thấp hơn .
và cũng
IX có nghĩa là ý định chỉ cập nhật một số hàng chứ không phải tất cả các hàng
vì vậy, đặt X
khóa trên đối tượng sau khi IX
trông RẤT đáng nghi với tôi.
Đầu tiên tôi đã cố gắng ngăn chặn bế tắc bằng cách cố gắng thêm gợi ý khóa bảng
MERGE INTO [Cache] WITH (HOLDLOCK, TABLOCK) T
và
MERGE INTO [Cache] WITH (HOLDLOCK, TABLOCKX) T
với TABLOCK
mô hình khóa tại chỗ trở thành
và với TABLOCKX
mẫu khóa là
vì hai SIX
(cũng như hai X
) không tương thích, điều này ngăn chặn bế tắc một cách hiệu quả, nhưng, thật không may, cũng ngăn ngừa đồng thời (điều không mong muốn).
Những nỗ lực tiếp theo của tôi là thêm PAGLOCK
và ROWLOCK
làm cho khóa trở nên chi tiết hơn và giảm sự tranh chấp. Cả hai đều không có tác dụng ( X
trên đối tượng vẫn được quan sát ngay sau đó IX
).
Nỗ lực cuối cùng của tôi là buộc hình dạng kế hoạch thực hiện "tốt" với khóa hạt tốt bằng cách thêm FORCESEEK
gợi ý
MERGE INTO [Cache] WITH (HOLDLOCK, FORCESEEK(IX_Cache(ItemKey))) T
va no đa hoạt động.
Và đây là phần thứ hai của câu hỏi phát sinh. Nó có thể xảy ra FORCESEEK
sẽ bị bỏ qua và mô hình khóa xấu sẽ được sử dụng? (Như tôi đã đề cập, PAGLOCK
và ROWLOCK
dường như bị bỏ qua).
Thêm UPDLOCK
không có tác dụng ( X
trên đối tượng vẫn có thể quan sát sau IX
).
Làm cho IX_Cache
chỉ số co cụm, như dự đoán, làm việc. Nó đã dẫn đến kế hoạch với Tìm kiếm chỉ số cụm và khóa hạt. Ngoài ra, tôi đã cố gắng ép Clustered Index Scan cũng cho thấy khóa hạt.
Tuy nhiên. Quan sát bổ sung. Trong thiết lập ban đầu ngay cả khi có FORCESEEK(IX_Cache(ItemKey)))
tại chỗ, nếu một thay đổi @itemKey
khai báo biến từ varchar (200) sang nvarchar (200) , kế hoạch thực hiện sẽ trở thành
thấy rằng tìm kiếm được sử dụng, mẫu khóa NHƯNG trong trường hợp này một lần nữa hiển thị X
khóa được đặt trên đối tượng sau IX
.
Vì vậy, có vẻ như việc tìm kiếm buộc không nhất thiết phải đảm bảo các khóa hạt (do đó không có sự bế tắc). Tôi không tự tin rằng việc có chỉ số phân cụm đảm bảo khóa hạt. Hay không?
Sự hiểu biết của tôi (sửa tôi nếu tôi sai) là việc khóa là tình huống ở một mức độ lớn và hình dạng kế hoạch thực hiện nhất định không bao hàm mô hình khóa nhất định.
Câu hỏi về điều kiện đặt X
khóa trên đối tượng sau khi IX
vẫn mở. Và nếu nó đủ điều kiện, có điều gì mà người ta có thể làm để ngăn chặn việc khóa đối tượng không?