Giúp hiểu lý do tại sao một bế tắc xảy ra trên khóa chỉ mục cấp hàng


7

Tôi có xml bế tắc sau

<deadlock>
  <victim-list>
    <victimProcess id="process3340d548c8" />
  </victim-list>
  <process-list>
    <process id="process3340d548c8" taskpriority="0" logused="1676" waitresource="KEY: 5:72057594083016704 (80e6876e1037)" waittime="4843" ownerId="6974726" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:16.627" XDES="0x330b1b4458" lockMode="U" schedulerid="1" kpid="34260" status="suspended" spid="201" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:16.657" lastbatchcompleted="2018-05-25T13:52:16.657" lastattention="1900-01-01T00:00:00.657" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6974726" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
      <executionStack>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
        AVH
    FROM
        [model].[AttributeValueHyperlink] AVH
    INNER JOIN
        @AttributeValueIdsTable AVT
    ON
        [AVT].EntityId = [AVH].AttributeValueI    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
        @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
        @AttributeValueIds = @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]      
            @ModelItemIdTabl    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="25" stmtstart="1088" stmtend="1302" sqlhandle="0x0300050061e52c65069dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete] 
        @ObjectIdTable,
        @MarkAsDeleted,
        @DeletedBy, 
        @DeletedO    </frame>
      </executionStack>
      <inputbuf>
Proc [Database Id = 5 Object Id = 1697441121]   </inputbuf>
    </process>
    <process id="process3330f29088" taskpriority="0" logused="1744" waitresource="KEY: 5:72057594083016704 (5b32eda0fe69)" waittime="4575" ownerId="6948390" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:14.370" XDES="0x331cb2c458" lockMode="U" schedulerid="2" kpid="29596" status="suspended" spid="181" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:14.403" lastbatchcompleted="2018-05-25T13:52:14.390" lastattention="1900-01-01T00:00:00.390" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6948390" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
      <executionStack>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
        AVH
    FROM
        [model].[AttributeValueHyperlink] AVH
    INNER JOIN
        @AttributeValueIdsTable AVT
    ON
        [AVT].EntityId = [AVH].AttributeValueI    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
        @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
        @AttributeValueIds = @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]      
            @ModelItemIdTabl    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Relationship_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="23" stmtstart="1078" stmtend="1302" sqlhandle="0x030005000d989e704f9dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete]
        @RelationshipIdTable,
        @MarkAsDeleted,
        @DeletedBy, 
        @DeletedO    </frame>
      </executionStack>
      <inputbuf>
Proc [Database Id = 5 Object Id = 1889441805]   </inputbuf>
    </process>
    <process id="process330f11fc28" taskpriority="0" logused="32948" waitresource="KEY: 5:72057594083016704 (80e6876e1037)" waittime="2558" ownerId="6941127" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:13.970" XDES="0x33199a4458" lockMode="U" schedulerid="2" kpid="91236" status="suspended" spid="193" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:21.987" lastbatchcompleted="2018-05-25T13:52:21.983" lastattention="1900-01-01T00:00:00.983" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6941127" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
      <executionStack>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
        AVH
    FROM
        [model].[AttributeValueHyperlink] AVH
    INNER JOIN
        @AttributeValueIdsTable AVT
    ON
        [AVT].EntityId = [AVH].AttributeValueI    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
        @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
        @AttributeValueIds = @AttributeValueId    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]      
            @ModelItemIdTabl    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Relationship_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="23" stmtstart="1078" stmtend="1302" sqlhandle="0x030005000d989e704f9dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete]
        @RelationshipIdTable,
        @MarkAsDeleted,
        @DeletedBy, 
        @DeletedO    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.RelationshipPair_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="21" stmtstart="1252" stmtend="1462" sqlhandle="0x03000500bc1cd015159eda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Relationship_Delete]
        @RelationshipIds,
        0,
        @DeletedBy,
        @DeletedOn,    </frame>
        <frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="20" stmtstart="878" stmtend="1076" sqlhandle="0x0300050061e52c65069dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[RelationshipPair_DeleteByModelItemIds]
        @ObjectIdTable,
        @DeletedBy,
        @DeletedO    </frame>
      </executionStack>
      <inputbuf>
Proc [Database Id = 5 Object Id = 1697441121]   </inputbuf>
    </process>
  </process-list>
  <resource-list>
    <keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f42880" mode="U" associatedObjectId="72057594083016704">
      <owner-list>
        <owner id="process3330f29088" mode="U" />
      </owner-list>
      <waiter-list>
        <waiter id="process3340d548c8" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
    <keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f4fb00" mode="X" associatedObjectId="72057594083016704">
      <owner-list>
        <owner id="process330f11fc28" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="process3330f29088" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
    <keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f42880" mode="U" associatedObjectId="72057594083016704">
      <owner-list>
        <owner id="process3340d548c8" mode="U" requestType="wait" />
      </owner-list>
      <waiter-list>
        <waiter id="process330f11fc28" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
  </resource-list>
</deadlock>

Theo như tôi có thể hiểu, chúng tôi có 3 khóa cấp hàng trên IX_AttributeValueHyperlink_AttributeValueIdchỉ mục. Tôi không chắc tại sao một số người trong số họ ( process330f11fc28) có khóa X trên chỉ mục này, nhưng những người khác thì không.

Ngoài ra kế hoạch thực hiện cho việc xóa này trông như thế này

kế hoạch thực hiện

Tôi không hiểu tại sao sự bế tắc đang xảy ra. Mọi thứ có vẻ ổn.

Nhân tiện, đây là trên cơ sở dữ liệu azl azure, do đó, nó sử dụng mức cô lập RCSI, tuy nhiên các giao dịch của chúng tôi được thiết lập (trong C#lớp) để sử dụng đọc cam kết.

Câu trả lời:


10

Tôi không hiểu tại sao sự bế tắc đang xảy ra.

Đối với kế hoạch thực hiện này, chuỗi các thao tác khóa liên quan đến việc xóa từng hàng là:

  1. U khóa chỉ mục không bao gồm (lấy tại tìm kiếm chỉ mục)
  2. U khóa chỉ mục cụm (lấy tại toán tử xóa)
  3. X khóa chỉ mục cụm (tại toán tử xóa)
  4. X khóa chỉ mục không bao gồm (tại toán tử xóa)

Tôi không chắc tại sao ... process330f11fc28 có khóa X trên chỉ mục này, nhưng những cái khác thì không.

Kế hoạch không có toán tử chặn, vì vậy nó là một đường ống đơn giản (đại khái, mỗi hàng sẽ đến cuối đường ống trước khi đường tiếp theo được xử lý).

Khi xảy ra bế tắc, một quy trình (phiên 193) có Xkhóa trên hàng chỉ mục không bao gồm (bước cuối cùng ở trên). Các phiên 181 và 201 đã bị chặn ở bước đầu tiên, cố gắng để có được một Ukhóa không tương thích trên cùng một phiên hàng chỉ mục không bao gồm phiên 193 đã bị khóa độc quyền.

Tôi xin lỗi trước rằng lời giải thích chi tiết có phần liên quan.

Khóa cập nhật nội bộ

Khóa cập nhật trên chỉ mục không bao gồm được động cơ lấy tự động để tránh một loại bế tắc chuyển đổi phổ biến , xảy ra khi hai quá trình có được một Skhóa trên cùng một tài nguyên, sau đó cả hai cố gắng chuyển đổi sang X. Mỗi cái được ngăn không cho chuyển đổi Ssang Xcái khác, vì vậy một bế tắc xảy ra.

Lấy một Ukhóa ngăn chặn điều này bởi vì Utương thích với Snhưng không phải là khác U. Các Skhóa tự nhiên thường không được thực hiện theo RCSI, nhưng các Ukhóa này là. Điều này tránh cố gắng cập nhật một phiên bản cũ của hàng.

Khóa tự động Uđược lấy theo RCSI chỉ trong trường hợp của bảng cung cấp bộ định vị hàng cho hoạt động cập nhật. Các bảng khác trong truy vấn (bao gồm mọi tham chiếu bổ sung cho mục tiêu cập nhật) tiếp tục sử dụng phiên bản hàng.

Các Ukhóa tự động này có tuổi thọ khác với các khóa cập nhật thông thường (chẳng hạn như có thể được thực hiện với một UPDLOCKgợi ý). UKhóa thông thường được tổ chức đến cuối giao dịch . UKhóa nội bộ được giữ đến cuối câu lệnh , ngoại trừ: nếu cùng một nhà điều hành kế hoạch đã lấy khóa có thể suy ra rằng hàng không đủ điều kiện để cập nhật, khóa sẽ được giải phóng ngay lập tức .

Xem bài viết của tôi Sửa đổi dữ liệu trong phần Đọc cách ly ảnh chụp đã cam kết .

Bế tắc tuần hoàn

UKhóa tự động này không cung cấp bảo vệ khỏi bế tắc theo chu kỳ . Hai giao dịch sửa đổi tài nguyên A và tài nguyên B trong một giao dịch, nhưng theo thứ tự ngược lại, được đảm bảo đến bế tắc:

  1. Giao dịch T1 sửa đổi hàng R1 (nhưng không cam kết hoặc hủy bỏ).
  2. Giao dịch T2 sửa đổi hàng R2 (nhưng không cam kết hoặc hủy bỏ).
  3. T1 cố gắng khóa hàng R2 và các khối (T2 có khóa không tương thích).
  4. T2 cố gắng khóa hàng R1 và các khối (T1 có khóa không tương thích).
  5. Bế tắc.

Trong đó "sửa đổi" ở trên bao gồm chèn, cập nhật, xóa, v.v.

Bế tắc cụ thể

Ví dụ trong câu hỏi là một biến thể về chủ đề này, trong đó:

  • Phiên 193 đã xóa hàng R1, giữ Xhàng đó
  • Phiên 193 đang chờ để có được Utrên hàng R2
  • Phiên 181 sở hữu Ukhóa trên R2
  • Phiên 181 đang chờ để có được Utrên R1
  • Bế tắc

(phiên 201 cũng đang chờ để có được Utrên hàng R2 nhưng đó là một người ngoài cuộc vô tội.)

Để rõ ràng: Chuỗi bế tắc chính xác ở trên không thể xảy ra đối với kế hoạch thực hiện chính xác được hiển thị trong câu hỏi. Phiên 181 không thể giữ UR2 và tiếp tục yêu cầu Utrên R1 do thiếu toán tử chặn và / hoặc phân tách giữa các điểm thu được và giải phóng cho Ukhóa không bao gồm. Bất kỳ Uhàng bị khóa nào được tìm thấy bởi tìm kiếm chỉ mục đều được đảm bảo chuyển đổi thành Xtrước khi hàng tìm kiếm tiếp theo được xử lý.

Tuy nhiên, chỉ vì đó là kế hoạch cho tuyên bố bây giờ, không có nghĩa đó là kế hoạch khi bế tắc xảy ra. Ví dụ: khi biên dịch lại mức câu lệnh xảy ra, SQL Server có thể thấy mức độ chính của biến bảng. Điều này cũng có thể dẫn đến một kế hoạch tham gia băm thay thế.

Kế hoạch tham gia Hash

Trong kế hoạch băm tham gia, các hàng từ biến bảng sẽ được sử dụng để xây dựng bảng băm. Sau khi hoàn thành, SQL Server có thể bắt đầu đọc các hàng từ đó AttributeValueHyperlink, Ukhóa trên mỗi hàng được phát ra bởi quá trình quét chỉ mục (hiện tại không có gì để tìm kiếm).

Tại phép nối băm, mỗi hàng phía đầu dò được đánh giá theo vị từ nối. Nếu một kết quả khớp được tìm thấy, hàng sẽ tiếp tục với toán tử Xóa chỉ mục cụm U, trong đó các khóa được phân cụm Xvà không Xkhóa được lấy như một phần của việc định vị và xóa các mục tương ứng với hàng hiện tại.

Tuy nhiên, nếu hàng không tham gia tại hàm băm, Ukhóa sẽ không được giải phóng. Các Ukhóa cho các hàng không liên kết sẽ tiếp tục tích lũy cho đến khi tất cả chúng được giải phóng khi câu lệnh hiện tại kết thúc. Đây chỉ đơn giản là hậu quả của các Ukhóa được thực hiện tại một toán tử (quét chỉ mục không bao gồm) nhưng được kiểm tra tính đủ điều kiện ở một khóa khác (phép nối băm).

Dù sao, nhiều Ukhóa làm cho bế tắc được báo cáo có thể.

Tránh bế tắc

Tất nhiên, kế hoạch các vòng lặp lồng đơn giản cũng có thể bị bế tắc khi xử lý cùng một dữ liệu (các khóa sẽ rõ ràng hơn là một bế tắc theo chu kỳ). Để tránh bế tắc, bạn cần đảm bảo các bộ đầu vào tách rời nhau hoặc các hàng trong mỗi bộ được xử lý theo đúng thứ tự (được sắp xếp theo cùng một cách và được xử lý theo cùng một chuỗi theo kế hoạch thực hiện).


1

Mỗi phiên sẽ xóa nhiều hàng khỏi cùng một bảng dựa trên giá trị trong một chỉ mục phụ. Ngay cả khi bạn không cố gắng xóa cùng một hàng trong nhiều phiên, các phiên sẽ tìm kiếm các hàng để xóa bằng chỉ mục phụ, đọc bằng khóa U và sau đó chuyển đổi thành khóa X cho mỗi hàng. Điều này tạo ra khả năng bế tắc.

Bạn có thể tránh điều này bằng cách tìm kiếm các hàng để xóa mà không có khóa U, sau đó xóa chúng trong một câu lệnh riêng. Một số hàng bạn tìm thấy trong truy vấn đầu tiên có thể bị xóa vào thời điểm bạn thử lần thứ hai. Nhưng có lẽ bạn không quan tâm đến điều đó.

Vì vậy, một cái gì đó như:

     declare @ids_to_delete table(id int)

     insert into @ids_to_delete(id)
     select id
     from [model].[AttributeValueHyperlink] AVH
     INNER JOIN @AttributeValueIdsTable AVT
     ON
        [AVT].EntityId = [AVH].AttributeValueI 

     delete from  [model].[AttributeValueHyperlink] 
     where id in (select id from @ids_to_delete)

Tôi đã thử điều này. Thật không may, nó chỉ đẩy vấn đề lên. Bây giờ tôi có một bế tắc cấp trang trên chính bảng (hay chính xác hơn là chỉ mục được nhóm).
Umair

Chà, bạn luôn có thể sử dụng gợi ý TABLOCK để đảm bảo rằng các XÓA chạy một phiên tại một thời điểm.
David Browne - Microsoft

Aha tôi thấy. Khi nào sẽ TABLOCKđược phát hành? Khi kết thúc tuyên bố xóa hoặc kết thúc giao dịch?
Umair
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.