2010-05-31 25 views
5

Tôi nhận được rất nhiều deadlocks trong ứng dụng web lớn của mình.Tôi có dữ liệu về deadlocks, nhưng tôi không thể hiểu tại sao chúng xảy ra

How to automatically re-run deadlocked transaction? (ASP.NET MVC/SQL Server)

Ở đây tôi muốn chạy lại giao dịch bế tắc, nhưng tôi đã nói để thoát khỏi sự bế tắc - đó là tốt hơn nhiều, hơn là cố gắng nắm bắt những sự bế tắc.

Vì vậy, tôi đã dành cả ngày với SQL Profiler, thiết lập các phím truy tìm vv Và đây là những gì tôi nhận được.

Có bảng Users. Tôi có một trang có thể sử dụng rất cao với các truy vấn sau đây (nó không phải là truy vấn mà thôi, nhưng đó là một trong những nguyên nhân gây khó khăn)

UPDATE Users 
SET views = views + 1 
WHERE ID IN (SELECT AuthorID FROM Articles WHERE ArticleID = @ArticleID) 

Và sau đó có các truy vấn sau đây trong ALL trang:

User = DB.Users.SingleOrDefault(u => u.Password == password && u.Name == username); 

Đó là nơi tôi nhận Người dùng từ cookie.

Rất thường xảy ra bế tắc và truy vấn LINQ-SQL thứ hai được chọn làm nạn nhân, vì vậy nó không chạy và người dùng trang web của tôi nhìn thấy màn hình lỗi.

Đây là thông tin từ biểu đồ .XDL bắt bởi SQL Profiler (Nó chỉ là bế tắc đầu tiên, nó không phải là người duy nhất Toàn bộ danh sách là khổng lồ..):

<deadlock-list> 
    <deadlock victim="process824df048"> 
     <process-list> 
      <process id="process824df048" taskpriority="0" logused="0" waitresource="PAGE: 7:1:13921" waittime="1830" ownerId="91418" transactionname="SELECT" lasttranstarted="2010-05-31T12:17:37.663" XDES="0x868175e0" lockMode="S" schedulerid="2" kpid="5076" status="suspended" spid="72" sbid="0" ecid="2" priority="0" trancount="0" lastbatchstarted="2010-05-31T12:17:37.663" lastbatchcompleted="2010-05-31T12:17:37.663" clientapp=".Net SqlClient Data Provider" hostname="WIN-S41KV2CLS67" hostpid="6920" isolationlevel="read committed (2)" xactid="91418" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
       <executionStack> 
        <frame procname="adhoc" line="1" stmtstart="74" sqlhandle="0x02000000de1cb30b5b2e40e31ffb345af3c7529430b559c2"> 
*password-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  </frame> 
        <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> 
unknown  </frame> 
       </executionStack> 
       <inputbuf> 
       </inputbuf> 
      </process> 
      <process id="process8765fb88" taskpriority="0" logused="216" waitresource="PAGE: 7:1:14196" waittime="1822" ownerId="91408" transactionname="UPDATE" lasttranstarted="2010-05-31T12:17:37.640" XDES="0x86978e90" lockMode="IX" schedulerid="2" kpid="5216" status="suspended" spid="73" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2010-05-31T12:17:37.557" lastbatchcompleted="2010-05-31T12:17:37.557" clientapp=".Net SqlClient Data Provider" hostname="WIN-S41KV2CLS67" hostpid="6920" loginname="sdfkj93jks9sl" isolationlevel="read committed (2)" xactid="91408" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
       <executionStack> 
        <frame procname="database.dbo.UpdateUserStats" line="31" stmtstart="1794" stmtend="2088" sqlhandle="0x03000700bac8836333e58f00879d00000100000000000000"> 
UPDATE Users 
    SET Views = Views + 1 
    WHERE ID IN (SELECT AuthorID FROM Articles WHERE ArticleID = @ArticleID)  </frame> 
        <frame procname="adhoc" line="1" stmtstart="84" sqlhandle="0x01000700b7c78e0760dd3f81000000000000000000000000"> 
EXEC @RETURN_VALUE = [dbo].[UpdateUserStats] @UserID = @p0 </frame> 
        <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> 
unknown  </frame> 
       </executionStack> 
       <inputbuf> 
(@p0 int,@RETURN_VALUE int output)EXEC @RETURN_VALUE = [dbo].[UpdateUserStats] @UserID = @p0 </inputbuf> 
      </process> 
      <process id="process86ce0988" taskpriority="0" logused="10000" waittime="1806" schedulerid="1" kpid="2604" status="suspended" spid="72" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2010-05-31T12:17:37.663" lastbatchcompleted="2010-05-31T12:17:37.663" clientapp=".Net SqlClient Data Provider" hostname="WIN-S41KV2CLS67" hostpid="6920" loginname="sdfkj93jks9sl" isolationlevel="read committed (2)" xactid="91418" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
       <executionStack> 
        <frame procname="adhoc" line="1" stmtstart="74" sqlhandle="0x02000000de1cb30b5b2e40e31ffb345af3c7529430b559c2"> 
*password-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  </frame> 
        <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> 
unknown  </frame> 
       </executionStack> 
       <inputbuf> 
*password-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- </inputbuf> 
      </process> 
     </process-list> 
     <resource-list> 
      <pagelock fileid="1" pageid="13921" dbid="7" objectname="database.dbo.Users" id="lock85535c80" mode="IX" associatedObjectId="72057594046382080"> 
       <owner-list> 
        <owner id="process8765fb88" mode="IX"/> 
       </owner-list> 
       <waiter-list> 
        <waiter id="process824df048" mode="S" requestType="wait"/> 
       </waiter-list> 
      </pagelock> 
      <pagelock fileid="1" pageid="14196" dbid="7" objectname="database.dbo.Users" id="lock8469f980" mode="SIU" associatedObjectId="72057594046382080"> 
       <owner-list> 
        <owner id="process86ce0988" mode="S"/> 
       </owner-list> 
       <waiter-list> 
        <waiter id="process8765fb88" mode="IX" requestType="convert"/> 
       </waiter-list> 
      </pagelock> 
      <exchangeEvent id="Pipe894b0680" WaitType="e_waitPipeGetRow" nodeId="0"> 
       <owner-list> 
        <owner id="process824df048"/> 
       </owner-list> 
       <waiter-list> 
        <waiter id="process86ce0988"/> 
       </waiter-list> 
      </exchangeEvent> 
     </resource-list> 
    </deadlock> 

Tôi đọc rất nhiều về sự bế tắc ... Và tôi không hiểu tại sao điều này lại gây ra bế tắc.

Vì vậy, rõ ràng cả hai truy vấn này đều chạy rất thường xuyên. Ít nhất một lần một giây. Có lẽ thậm chí thường xuyên hơn (300-400 người dùng trực tuyến). Vì vậy, chúng có thể chạy cùng một lúc rất dễ dàng, nhưng tại sao nó gây ra bế tắc? Hãy giúp tôi.

Cảm ơn bạn

+1

Bạn có đang sử dụng SQL2005 trở lên không? Nếu vậy bạn đã nhận được biểu đồ Deadlock từ SQL Profiler? Ngoài ra, bạn có biết mức độ cô lập giao dịch mà các truy vấn của bạn đang chạy không? –

+0

Có tôi đã nhận được đồ thị. Đó là nơi tôi nhận được thông tin này từ. Tôi không biết gì về việc cô lập giao dịch.Tôi có thể kiểm tra nó ở đâu? – Alex

+1

Trong dấu vết profiler nhấp chuột phải vào sự kiện biểu đồ bế tắc và chọn trích xuất dữ liệu sự kiện, lưu nó dưới dạng xml. Sau đó, mở nó trong notepad và tìm "isolationlevel" –

Trả lời

11

Bạn cần chụp biểu đồ bế tắc. Đính kèm Profiler và nắm bắt lớp Deadlock Graph Event. Lưu đồ thị .XDL và thêm thông tin đó vào bài đăng của bạn.

Cho đến lúc đó, hiển nhiên là người dùng DB.Users của bạn.truy vấn SingleOrDefault đòi hỏi một chỉ mục trên danh ít nhất, nếu không muốn nói về Tên và Mật khẩu:

CREATE INDEX idxUsersNamePassword on Users(Name,Password); 

Tôi hy vọng người dùng đã có một chỉ mục trên ID, và các Điều có một chỉ mục trên ArticleID trong đó bao gồm AuthorID quá. Giả sử Users.ID và Articles.ArticleID là PK trong các bảng tương ứng, chúng có lẽ là khóa được nhóm tương ứng để nó đúng. Nó có giá trị gấp đôi kiểm tra, mặc dù.

Và, như tôi đã trả lời bạn một lần trong bài trước của bạn, bạn quyết định chuyển vào và rời bỏ trả lời, bạn nên xem xét bật Snapshot Isolation:

ALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON 

Bên cạnh đó, lưu trữ mật khẩu trong văn bản rõ ràng là một #fail lớn.

Cập nhật sau khi thông tin bế tắc

Có ba quá trình (yêu cầu):

  • A) ... F048 mà đang chạy SELECT ... FROM Users WHERE Password = ... and Name = ...
  • B) ... 0988 đó là chạy số SELECT ... FROM Users WHERE Password = ... and Name = ...
  • C) ... FB88 đang chạy UPDATE ...

Chu kỳ bế tắc là:

  1. C đợi trên khóa Trang IX, bị chặn bởi A của S khóa
  2. chờ đợi B trên trang S khóa, bị chặn bởi khóa IX C
  3. Một đợi trên song song tài nguyên trao đổi, bị chặn bởi B

Do đó chu kỳ là C-> A-> B-> C. Từ một thực tế là hai CHỌN liên quan quyết định 1) sử dụng một kế hoạch song song và 2) sử dụng khóa trang rõ ràng là họ thực hiện quét toàn bộ đầu cuối của toàn bộ bảng Người dùng. do đó, vấn đề là, như tôi đã dự đoán, thiếu chỉ mục trên (Tên, Mật khẩu) trên Người dùng khiến cho truy vấn quét quá nhiều dữ liệu. Việc thêm chỉ mục sẽ biến SELECT thành SEEK thẳng trên chỉ mục Nc và tra cứu chỉ mục Clustered, và điều này sẽ làm giảm đáng kể cửa sổ chồng lên với UPDATE. Hiện tại, CẬP NHẬT được đảm bảo khá nhiều xung đột với tất cả các lựa chọn, vì mọi SELECT đều được bảo đảm để đọc mọi hàng.

Việc thêm chỉ mục sẽ làm giảm bớt vấn đề trước mắt. Sử dụng cách ly Ảnh chụp sẽ mặt nạ sự cố, do quét từ đầu đến cuối sẽ vẫn xảy ra trừ khi chỉ mục (Tên, Mật khẩu) được thêm vào. Hoặc chỉ (Tên) cũng có khả năng hoạt động.

Để có khả năng mở rộng trong tương lai, việc cập nhật cột Chế độ xem trên mỗi lần xem trang sẽ không hoạt động. Cập nhật chậm trễ, cập nhật tổng hợp hàng loạt, phân vùng theo chiều dọc bảng Người dùng và đưa ra cột Chế độ xem là các lựa chọn thay thế khả thi.

+1

Xin lỗi, tôi quên chấp nhận câu trả lời của bạn. Có, tôi sẽ cập nhật hệ thống lưu trữ mật khẩu. Tôi sẽ cập nhật câu hỏi của mình với thông tin .XDL. – Alex

+0

.XDL thông tin được đăng. – Alex

+0

Cảm ơn bạn rất nhiều vì câu trả lời chi tiết như vậy! Tôi chưa bao giờ bắt gặp lập chỉ mục bất kỳ cột nào khác với các khóa chính. Tôi cần phải làm gì để thêm chỉ mục (Tên, Mật khẩu)? Tôi đã tìm thấy cửa sổ chỉ mục/khóa trong trình thiết kế bảng. Nó có khóa PK_Users và tôi có thể thêm khóa IX_Users cho tên người dùng, nhưng làm cách nào tôi có thể kết hợp nó với mật khẩu? Cảm ơn bạn một lần nữa. – Alex

1

vấn đề của bạn có rất nhiều điểm tương đồng với điều đó ở đây Diagnosing Deadlocks in SQL Server 2005

(LINQ to SQL, Read Only giao dịch bị bế tắc bởi một Write giao dịch đọc)

Nếu bạn đang ở trên SQL2005 hoặc sau này có lẽ thiết lập sự cô lập ảnh chụp như được thảo luận về chủ đề đó sẽ thực hiện công việc. Nếu không, vui lòng cập nhật bài đăng của bạn với các chi tiết về phiên bản bạn đang sử dụng.

+0

Cảm ơn, tôi sẽ có một cái nhìn. – Alex

1

Trong trường hợp này (nghĩa là loại dữ liệu bạn đang đọc và bản chất của các cập nhật xảy ra trên dữ liệu đó), tôi sẽ chạy truy vấn tra cứu người dùng ở chế độ cô lập không được cam kết.

Ngoài ra, một thay đổi có liên quan hơn. Từ mô tả bạn đã đăng, tôi sẽ xem xét việc không duy trì số lượt xem trên hồ sơ người dùng. Thay vào đó, tôi sẽ ghi lại ViewCount chống lại Bài viết, sau đó dervive tổng số lượt xem cho một người dùng từ tổng của Articles.ViewCount bởi AuthorID.

Các vấn đề liên quan