Những lý do tốt để sử dụng CHỌN CHỌN VỚI XLOCK?


11

Tôi đang đối mặt với một số bế tắc xảy ra lại, một trong số đó là Khóa phím và chứa truy vấn CHỌN với gợi ý XLOCK trở thành nạn nhân bế tắc. Câu lệnh còn lại là một CHERTN vào một trong các bảng là một phần của khung nhìn của truy vấn đầu tiên.

Lượt xem:

create view dbo.viewE
 as
    select * from dbo.E  
    where myValue > 13000 

Chọn truy vấn:

select * from dbo.viewE with (XLOCK) where A > GETUTCDATE() 

Tuyên bố INSERT:

INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())

Bảng bên dưới dbo.E đang giữ khoảng 3 triệu hàng trong khoảng 20 cột, một số trong số đó là ntext.

Lấy các truy vấn ra và mô phỏng nó bằng tay với hai giao dịch, hành vi được tái sản xuất. Hành vi thay đổi nếu XLOCK bị xóa khỏi phần chọn.

Đồ thị bế tắc:

<deadlock-list>
 <deadlock victim="process222222221">
  <process-list>
   <process id="process222222221" taskpriority="0" logused="0" waitresource="KEY: 5:72057604035644444 (ccdf51accc0c)" waittime="2522" ownerId="27202256401" transactionname="SELECT" lasttranstarted="2015-09-14T16:32:36.160" XDES="0x2f1ec5ca0" lockMode="RangeX-X" schedulerid="15" kpid="12936" status="suspended" spid="359" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2015-09-14T16:32:36.160" lastbatchcompleted="2015-09-14T16:32:36.160" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="serializable (4)" xactid="27202256401" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="48" sqlhandle="0x02000000611e4523142b2318c47c87313a9b2ba587ff3130">
        SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()      </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()    </inputbuf>
   </process>
   <process id="process6022222" taskpriority="0" logused="161152" waitresource="KEY: 5:72057604035644444 (cd874c2ba438)" waittime="1370" ownerId="27202248438" transactionguid="0x8de5ccd6eeef67469c6234af59e44ca5" transactionname="DTCXact" lasttranstarted="2015-09-14T16:32:34.767" XDES="0x4aa0bf950" lockMode="RangeI-N" schedulerid="14" kpid="6636" status="suspended" spid="329" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-09-14T16:32:37.300" lastbatchcompleted="2015-09-14T16:32:37.300" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="read uncommitted (1)" xactid="27202248438" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="936" sqlhandle="0x020000004853462f09790a4ddedc0d574c2afa539aef1c0e">
     INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock258b6dc80" mode="X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process6022222" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process222222221" mode="RangeX-X" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock7b145c400" mode="RangeX-X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process222222221" mode="RangeX-X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6022222" mode="RangeI-N" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

Theo tôi hiểu điều này, tôi đang xem xét một bế tắc KEYLOCK về cơ bản gây ra bởi một truy vấn chỉ mục chưa được phát hiện sử dụng một chỉ mục không được bao gồm và một cụm để thu thập các giá trị cần thiết, phải không?

Những câu hỏi của tôi:

  1. Tôi không thể tạo chỉ mục bao phủ vì các cột NTEXT được yêu cầu có liên quan. Sẽ giảm mạnh số lượng hàng giúp ở đây?
  2. Có lý do chính đáng nào mà tôi không biết CHỌN được thực thi với XLOCK không? Bế tắc cũng sẽ xảy ra mà không có XLOCK?

Câu trả lời:


15

Theo tôi hiểu điều này, tôi đang xem xét một bế tắc KEYLOCK về cơ bản gây ra bởi một truy vấn chỉ mục chưa được phát hiện sử dụng một chỉ mục không được bao gồm và một cụm để thu thập các giá trị cần thiết, phải không?

Về cơ bản, có. Thao tác đọc (chọn) truy cập vào chỉ mục không bao gồm trước, sau đó là chỉ mục được nhóm (tra cứu). Thao tác ghi (insert) truy cập vào chỉ mục được nhóm trước, sau đó là chỉ mục không được bao gồm. Truy cập cùng một tài nguyên theo một thứ tự khác giữ các khóa không tương thích có thể dẫn đến bế tắc.

Sẽ giảm mạnh số lượng hàng giúp ở đây?

thể , vì ít tài nguyên bị khóa hơn và hoạt động sẽ có xu hướng hoàn thành nhanh hơn. Nếu nó giúp, nó có thể làm giảm bế tắc, nhưng rất có thể không loại bỏ chúng (nhưng đọc tiếp).

Có lý do chính đáng nào mà tôi không biết CHỌN được thực thi với XLOCK không?

Không hẳn vậy. Những gợi ý khóa như thế này thường được giới thiệu bởi những người không có sự hiểu biết đầy đủ về cách cô lập, khóa và khóa chết, trong một nỗ lực tuyệt vọng để giảm hoặc loại bỏ một vấn đề.

Bế tắc cũng sẽ xảy ra mà không có XLOCK?

Không , nếu lựa chọn thực sự chạy khi đọc cách ly không được cam kết vì các khóa không tương thích sẽ không được thực hiện (và giữ) theo một thứ tự khác.

Đúng , nếu mức cách ly khóa được sử dụng và các khóa không tương thích được lấy và giữ theo thứ tự không nhất quán, ví dụ như chia sẻ (S) trên không được bao gồm, sau đó S trên cụm khi đọc. Khả năng bế tắc trong kịch bản này phụ thuộc vào số lượng khóa được thực hiện và thời gian chúng được giữ trong bao lâu.

Lời khuyên

Điều thực sự nổi bật (đang xem xét) là giao dịch được chọn đang chạy theo sự cô lập tuần tự hóa . Điều đó có thể được đặt theo khung của bạn hoặc do sử dụng DTC (Điều phối viên giao dịch phân tán) - xem giao dịch = "DTCXact" trong biểu đồ khóa chết. Bạn nên xem xét các lý do cho việc này, và tìm cách thay đổi nó nếu có thể.

Nếu không có sự leo thang này thành tuần tự hóa, rất có thể rất tốt là sự bế tắc này sẽ không xảy ra, giả sử XLOCKgợi ý được loại bỏ. Điều đó nói rằng, bạn sẽ được đọc dưới đọc không cam kết sự cô lập , đi kèm với rất ít đảm bảo tính nhất quán.

Nếu ứng dụng và mã SQL Server của bạn có thể chấp nhận các phiên bản đọc của các hàng, hãy thay đổi thành đọc cách ly ảnh chụp nhanh đã cam kết (RCSI) hoặc cách ly ảnh chụp nhanh (SI) cho các lần đọc cũng sẽ tránh được bế tắc (XLOCK bị loại bỏ!), Trong khi đưa ra một điểm nhất quán, bị loại bỏ thời gian xem dữ liệu đã cam kết Điều này cũng cho rằng bạn có thể tránh sự cô lập nối tiếp, tất nhiên.

Cuối cùng, XLOCKgợi ý phản tác dụng, nhưng bạn thực sự cần xem xét lý do của việc sử dụng mức cô lập tuần tự hóa. Điều trancount = 2này cũng thú vị - có lẽ bạn đang vô tình làm giao dịch lồng nhau ở đây. Một cái gì đó khác để kiểm tra.


2
  1. Giảm mạnh số lượng hàng sẽ giảm khả năng gặp bế tắc, nhưng nó sẽ không biến mất hoàn toàn.

Nói một cách đơn giản, đầu tiên chọn là sử dụng chỉ mục để xác định các hàng cần chọn, sau đó tìm nạp các hàng, trong khi chèn đang chèn một hàng, sau đó cố gắng cập nhật chỉ mục (XLOCKED).

  1. Các nhà phát triển ứng dụng có xu hướng sử dụng XLOCK nếu trong cùng một giao dịch họ muốn thực hiện cập nhật dữ liệu. Điều này đảm bảo không ai có thể cập nhật dữ liệu theo chúng. Tôi sẽ điều tra những gì ứng dụng đang làm để xem XLOCK có bắt buộc không.

Đã nói điều này, loại bỏ XLOCK có thể sẽ không giải quyết vấn đề. CHỌN vẫn sẽ lấy ra một khóa chia sẻ trên chỉ mục và INSERT sẽ muốn có một XLOCK để cập nhật nó. Khóa chung và XLOCK không thể tồn tại trên đối tượng cùng nhau, do đó bạn vẫn sẽ gặp bế tắc. IX_Index1 phải là MyValue hoặc A hoặc cả hai.

Loại bế tắc này thường xảy ra do các chỉ mục được thiết kế kém và / hoặc quá nhiều chỉ mục. Hoặc viết mã kém. Tùy chọn tốt nhất của bạn là để xem liệu có cách nào đó lựa chọn có thể được viết lại để sử dụng chỉ mục khác hay không.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.