Tôi đang giải quyết vấn đề bế tắc trong khi tôi nhận thấy hành vi khóa là khác nhau khi tôi sử dụng chỉ mục được phân cụm và không phân cụm trên trường id. Vấn đề bế tắc dường như được giải quyết nếu chỉ số clusty hoặc khóa chính được áp dụng cho trường id.
Tôi có các giao dịch khác nhau thực hiện một hoặc nhiều cập nhật cho các hàng khác nhau, ví dụ: giao dịch A sẽ chỉ cập nhật hàng có ID = a, tx B sẽ chỉ chạm vào hàng có ID = b, v.v.
Và tôi đã hiểu rằng nếu không có chỉ mục, bản cập nhật sẽ có được khóa cập nhật cho tất cả các hàng và chuyển sang khóa độc quyền khi cần thiết, điều này cuối cùng sẽ dẫn đến bế tắc. Nhưng tôi không tìm hiểu tại sao với chỉ số không được phân cụm, bế tắc vẫn còn đó (mặc dù tỷ lệ trúng dường như bị giảm)
Bảng dữ liệu:
CREATE TABLE [dbo].[user](
[id] [int] IDENTITY(1,1) NOT NULL,
[userName] [nvarchar](255) NULL,
[name] [nvarchar](255) NULL,
[phone] [nvarchar](255) NULL,
[password] [nvarchar](255) NULL,
[ip] [nvarchar](30) NULL,
[email] [nvarchar](255) NULL,
[pubDate] [datetime] NULL,
[todoOrder] [text] NULL
)
Dấu vết bế tắc
deadlock-list
deadlock victim=process4152ca8
process-list
process id=process4152ca8 taskpriority=0 logused=0 waitresource=RID: 5:1:388:29 waittime=3308 ownerId=252354 transactionname=user_transaction lasttranstarted=2014-04-11T00:15:30.947 XDES=0xb0bf180 lockMode=U schedulerid=3 kpid=11392 status=suspended spid=57 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2014-04-11T00:15:30.953 lastbatchcompleted=2014-04-11T00:15:30.950 lastattention=1900-01-01T00:00:00.950 clientapp=.Net SqlClient Data Provider hostname=BOOD-PC hostpid=9272 loginname=getodo_sql isolationlevel=read committed (2) xactid=252354 currentdb=5 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=62 sqlhandle=0x0200000062f45209ccf17a0e76c2389eb409d7d970b0f89e00000000000000000000000000000000
update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@owner
frame procname=unknown line=1 sqlhandle=0x00000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@para0 nvarchar(2)<c/>@owner int)update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@owner
process id=process4153468 taskpriority=0 logused=4652 waitresource=KEY: 5:72057594042187776 (3fc56173665b) waittime=3303 ownerId=252344 transactionname=user_transaction lasttranstarted=2014-04-11T00:15:30.920 XDES=0x4184b78 lockMode=U schedulerid=3 kpid=7272 status=suspended spid=58 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2014-04-11T00:15:30.960 lastbatchcompleted=2014-04-11T00:15:30.960 lastattention=1900-01-01T00:00:00.960 clientapp=.Net SqlClient Data Provider hostname=BOOD-PC hostpid=9272 loginname=getodo_sql isolationlevel=read committed (2) xactid=252344 currentdb=5 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtstart=60 sqlhandle=0x02000000d4616f250747930a4cd34716b610a8113cb92fbc00000000000000000000000000000000
update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@uid
frame procname=unknown line=1 sqlhandle=0x00000000000000000000000000000000000000000000000000000000000000000000000000000000
unknown
inputbuf
(@para0 nvarchar(61)<c/>@uid int)update [user] WITH (ROWLOCK) set [todoOrder]=@para0 where id=@uid
resource-list
ridlock fileid=1 pageid=388 dbid=5 objectname=SQL2012_707688_webows.dbo.user id=lock3f7af780 mode=X associatedObjectId=72057594042122240
owner-list
owner id=process4153468 mode=X
waiter-list
waiter id=process4152ca8 mode=U requestType=wait
keylock hobtid=72057594042187776 dbid=5 objectname=SQL2012_707688_webows.dbo.user indexname=10 id=lock3f7ad700 mode=U associatedObjectId=72057594042187776
owner-list
owner id=process4152ca8 mode=U
waiter-list
waiter id=process4153468 mode=U requestType=wait
Ngoài ra một phát hiện thú vị và có thể liên quan là chỉ số phân cụm và không phân cụm dường như có các hành vi khóa khác nhau
Khi sử dụng chỉ mục được nhóm, có một khóa độc quyền trên khóa cũng như khóa độc quyền trên RID khi cập nhật, dự kiến; trong khi có hai khóa độc quyền trên hai RID khác nhau nếu sử dụng chỉ mục không phân cụm, điều này làm tôi bối rối.
Sẽ hữu ích nếu bất cứ ai có thể giải thích tại sao về điều này quá.
Kiểm tra SQL:
use SQL2012_707688_webows;
begin transaction;
update [user] with (rowlock) set todoOrder='{1}' where id = 63501
exec sp_lock;
commit;
Với id là Chỉ mục cụm:
spid dbid ObjId IndId Type Resource Mode Status
53 5 917578307 1 KEY (b1a92fe5eed4) X GRANT
53 5 917578307 1 PAG 1:879 IX GRANT
53 5 917578307 1 PAG 1:1928 IX GRANT
53 5 917578307 1 RID 1:879:7 X GRANT
Với id là Chỉ mục không phân cụm
spid dbid ObjId IndId Type Resource Mode Status
53 5 917578307 0 PAG 1:879 IX GRANT
53 5 917578307 0 PAG 1:1928 IX GRANT
53 5 917578307 0 RID 1:879:7 X GRANT
53 5 917578307 0 RID 1:1928:18 X GRANT
EDIT1: Chi tiết về sự bế tắc không có chỉ số
Nói rằng tôi có hai tx A và B, mỗi câu có hai câu lệnh cập nhật, hàng khác nhau của khóa học
tx A
update [user] with (rowlock) set todoOrder='{1}' where id = 63501
update [user] with (rowlock) set todoOrder='{2}' where id = 63501
tx B
update [user] with (rowlock) set todoOrder='{3}' where id = 63502
update [user] with (rowlock) set todoOrder='{4}' where id = 63502
{1} và {4} sẽ có cơ hội bế tắc, vì
tại {1}, khóa U được yêu cầu cho hàng 63502 vì nó cần thực hiện quét bảng và khóa X có thể được giữ ở hàng 63501 vì nó phù hợp với điều kiện
tại {4}, khóa U được yêu cầu cho hàng 63501 và khóa X đã được giữ cho 63502
vì vậy chúng ta có txA giữ 63501 và chờ 63502 trong khi txB giữ 63502 chờ 63501, đó là một bế tắc
EDIT2: Hóa ra một lỗi trong trường hợp thử nghiệm của tôi tạo ra một tình huống khác biệt ở đây Xin lỗi vì sự nhầm lẫn nhưng lỗi này tạo ra một tình huống khác biệt và cuối cùng dường như gây ra bế tắc.
Vì phân tích của Paul thực sự đã giúp tôi trong trường hợp này nên tôi sẽ chấp nhận đó là câu trả lời.
Do lỗi của trường hợp thử nghiệm của tôi, hai giao dịch txA và txB có thể cập nhật cùng một hàng, như sau:
tx A
update [user] with (rowlock) set todoOrder='{1}' where id = 63501
update [user] with (rowlock) set todoOrder='{2}' where id = 63501
tx B
update [user] with (rowlock) set todoOrder='{3}' where id = 63501
{2} và {3} sẽ có cơ hội bế tắc khi:
txA yêu cầu khóa U trên khóa trong khi giữ khóa X trên RID (do cập nhật {1}) txB yêu cầu khóa U trên RID trong khi giữ khóa U trên khóa