Cập nhật chỉ mục máy chủ SQL


13

Tôi có 2 truy vấn mà khi chạy cùng lúc đang gây ra bế tắc.

Truy vấn 1 - cập nhật một cột được bao gồm trong một chỉ mục (index1):

update table1 set column1 = value1 where id = @Id

Lấy X-Lock trên bảng1 sau đó thử X-Lock trên index1.

Truy vấn 2:

select columnx, columny, etc from table1 where {some condition}

Lấy S-Lock trên index1 sau đó thử S-Lock trên bảng1.

Có cách nào để ngăn chặn sự bế tắc trong khi duy trì các truy vấn tương tự không? Ví dụ: bằng cách nào đó tôi có thể lấy X-Lock trên chỉ mục trong giao dịch cập nhật trước khi cập nhật để đảm bảo truy cập bảng và chỉ mục theo cùng một thứ tự - điều này sẽ ngăn chặn bế tắc?

Mức cô lập được đọc Cam kết. Khóa hàng và khóa trang được kích hoạt cho các chỉ mục. Có thể cùng một bản ghi đang tham gia vào cả hai truy vấn - Tôi không thể biết từ biểu đồ khóa chết vì nó không hiển thị các tham số.

Đồ thị bế tắc

Câu trả lời:


11

Có cách nào để ngăn chặn sự bế tắc trong khi duy trì các truy vấn tương tự không?

Biểu đồ khóa chết cho thấy bế tắc cụ thể này là một bế tắc chuyển đổi được liên kết với tra cứu dấu trang (tra cứu RID trong trường hợp này):

Đồ thị bế tắc

Như câu hỏi lưu ý, rủi ro bế tắc chung phát sinh do các truy vấn có thể có được các khóa không tương thích trên cùng một tài nguyên theo các thứ tự khác nhau. Các SELECTtruy vấn cần phải truy cập vào các chỉ số trước khi bàn do sự tra cứu RID, trong khi UPDATESửa truy vấn bảng đầu tiên, sau đó chỉ số.

Loại bỏ bế tắc đòi hỏi phải loại bỏ một trong các thành phần bế tắc. Sau đây là các tùy chọn chính:

  1. Tránh tra cứu RID bằng cách bao phủ chỉ mục không bao gồm. Điều này có thể không thực tế trong trường hợp của bạn vì SELECTtruy vấn trả về 26 cột.
  2. Tránh tra cứu RID bằng cách tạo một chỉ mục cụm. Điều này sẽ liên quan đến việc tạo một chỉ mục cụm trên cột Proposal. Điều này đáng để xem xét, mặc dù có vẻ như cột này thuộc loại uniqueidentifier, có thể hoặc không phải là một lựa chọn tốt cho một chỉ mục được nhóm, tùy thuộc vào các vấn đề rộng hơn.
  3. Tránh lấy các khóa được chia sẻ khi đọc bằng cách bật tùy chọn READ_COMMITTED_SNAPSHOThoặc SNAPSHOTcơ sở dữ liệu. Điều này sẽ yêu cầu kiểm tra cẩn thận, đặc biệt là đối với mọi hành vi chặn được thiết kế sẵn. Mã kích hoạt cũng sẽ yêu cầu thử nghiệm để đảm bảo logic thực hiện chính xác.
  4. Tránh lấy các khóa được chia sẻ khi đọc bằng cách sử dụng READ UNCOMMITTEDmức cô lập cho SELECTtruy vấn. Tất cả các hãy cẩn thận thông thường áp dụng.
  5. Tránh thực hiện đồng thời hai truy vấn được đề cập bằng cách sử dụng khóa ứng dụng độc quyền (xem sp_getapplock ).
  6. Sử dụng gợi ý khóa bảng để tránh đồng thời. Đây là một cái búa lớn hơn tùy chọn 5, vì nó có thể ảnh hưởng đến các truy vấn khác, không chỉ hai truy vấn được xác định trong câu hỏi.

Tôi bằng cách nào đó có thể lấy X-Lock trên chỉ mục trong giao dịch cập nhật trước khi cập nhật để đảm bảo truy cập bảng và chỉ mục theo cùng một thứ tự

Bạn có thể thử điều này, bằng cách gói cập nhật trong một giao dịch rõ ràng và thực hiện SELECTvới một XLOCKgợi ý về giá trị chỉ mục không bao gồm trước khi cập nhật. Điều này phụ thuộc vào bạn biết chắc chắn giá trị hiện tại trong chỉ mục không bao gồm là gì, làm cho kế hoạch thực hiện đúng và dự đoán chính xác tất cả các tác dụng phụ của việc sử dụng khóa bổ sung này. Nó cũng dựa vào công cụ khóa không đủ thông minh để tránh mất khóa nếu nó được đánh giá là dư thừa .

Tóm lại, trong khi nguyên tắc này là khả thi, tôi không khuyên bạn nên dùng nó. Thật quá dễ dàng để bỏ lỡ một cái gì đó, hoặc vượt qua chính mình theo những cách sáng tạo. Nếu bạn thực sự phải tránh những bế tắc này (thay vì chỉ phát hiện ra chúng và thử lại), tôi sẽ khuyến khích bạn xem xét các giải pháp tổng quát hơn được liệt kê ở trên.


Từ việc nhìn sâu hơn vào vấn đề tôi nghĩ rằng để nó không thay đổi có lẽ là tốt nhất. Đó là một vấn đề phổ biến hơn mà ban đầu tôi nhận ra.
Dale K

1

Tôi có một vấn đề tương tự thỉnh thoảng xảy ra và đây là cách tiếp cận tôi thực hiện.

  1. Thêm set deadlock priority low;vào lựa chọn. Điều này sẽ khiến truy vấn này trở thành nạn nhân bế tắc khi xảy ra bế tắc.
  2. Thiết lập logic thử lại trong ứng dụng của bạn để tự động thử lại lựa chọn nếu thất bại do bế tắc (hoặc hết thời gian), sau khi chờ / ngủ trong một khoảng thời gian ngắn để cho phép các truy vấn chặn hoàn thành.

Lưu ý: nếu bạn selectlà một phần của giao dịch đa tuyên bố rõ ràng, thì bạn cần chắc chắn thử lại toàn bộ giao dịch và không chỉ là tuyên bố thất bại, nếu không bạn có thể nhận được một số kết quả không mong muốn. Nếu đây là một single selectsau đó bạn cũng tốt, nhưng nếu đó là tuyên bố xcủa ntrong một giao dịch, sau đó chỉ cần chắc chắn rằng bạn thử tất cả các nbáo cáo trong thời gian thử lại.


Cảm ơn - các truy vấn được tự động bế tắc nạn nhân theo mặc định. Và vâng, chúng tôi đã có một cơ chế thử lại mạnh mẽ.
Dale K
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.