2011-01-03 28 views
14

Đây thực sự là một cuộc thảo luận nhiều hơn một câu hỏi cụ thể về nolock.Để NOLOCK hoặc KHÔNG để NOLOCK, đó là câu hỏi

Tôi đã tiếp quản một ứng dụng gần đây rằng hầu hết mọi truy vấn (và có rất nhiều truy vấn) có tùy chọn nolock trên chúng. Bây giờ tôi khá mới với máy chủ SQL (sử dụng Oracle trong 10 năm) nhưng tôi thấy điều này khá đáng lo ngại. Vì vậy, cuối tuần này tôi đã nói chuyện với một trong những người bạn của tôi điều hành một trang web thương mại điện tử khá lớn (tên sẽ bị giữ lại để bảo vệ tội) và anh ta nói anh ta phải làm điều này với tất cả các máy chủ SQL của mình.

Đây có phải là sự sụp đổ rất ngắn với máy chủ SQL không? Đây có phải chỉ là một thất bại trong thiết kế DB (tôi không phải là cấp 3, nhưng gần gũi của nó) Có ai ra có chạy một ứng dụng máy chủ SQL mà không có nolocks? Đây là những vấn đề mà Oracle xử lý tốt hơn với các bản ghi lớn hơn.

Máy chủ SQL không thể xử lý các tải trọng lớn? Có cách giải quyết nào tốt hơn đọc dữ liệu không được kiểm soát không? Tôi rất thích nghe những gì mọi người nghĩ.

Cảm ơn

Trả lời

13

SQL Server đã được thêm vào snapshot isolation trong SQL Server 2005, điều này sẽ cho phép bạn vẫn đọc các giá trị chính xác mới nhất mà không cần phải chờ đợi cho ổ khóa. StackOverflow cũng sử dụng cách ly Snapshot. Mức độ cô lập Snapshot ít nhiều giống như Oracle sử dụng, đây là lý do tại sao deadlocks không phải là rất phổ biến trên một hộp Oracle. Chỉ cần lưu ý để có nhiều không gian tempdb nếu bạn kích hoạt nó

từ Sách On Line

Khi tùy chọn cơ sở dữ liệu READ_COMMITTED_SNAPSHOT được thiết lập ON, đọc ly cam kết sử dụng hàng phiên bản để cung cấp Câu lệnh cấp độ đọc tính nhất quán. Hoạt động đọc chỉ yêu cầu ổ khóa bảng SCH-S và không có khóa trang hoặc hàng. Khi tùy chọn READ_COMMITTED_SNAPSHOT cơ sở dữ liệu được đặt thành TẮT, là cài đặt mặc định , hãy đọc cam kết cách ly hoạt động như đã thực hiện trong các phiên bản trước đó của của SQL Server. Cả hai triển khai đều đáp ứng định nghĩa ANSI về cam kết đã đọc cách ly.

+0

Với ảnh chụp nhanh hoạt động, cơ hội bạn gặp phải bế tắc là gì? Tôi sẽ không đề nghị rằng bạn có thể cho tôi một phần trăm, nhưng bạn đã bao giờ chạy vào bế tắc với nó đang chạy chưa? – Limey

+0

Nó dường như đã cố định vấn đề StackOverflow, bản thân tôi đã không nhìn thấy deadlocks với nó, nhưng tôi cũng thực hiện một số thực hành tốt nhất về lập trình máy chủ SQL mà giảm thiểu điều này để bắt đầu với – SQLMenace

+0

Không phải luôn luôn là một ý tưởng tốt ... http: // sqlblogcasts .com/blogs/tonyrogerson/archive/2006/11/16/1345.aspx – gbn

4

Không, không cần sử dụng NOLOCK. Liên kết: SO 1

Đối với tải, chúng ta đối phó với 2000 hàng mỗi thứ hai được thay đổi nhỏ so với 35k TPS

Deadlocks là do ganh đua khóa và thường gây ra bởi trật tự ghi không phù hợp trên bảng trong các giao dịch. ORM đặc biệt là rác ở đây. Chúng tôi nhận được chúng rất thường xuyên. Một DAL cũng bằng văn bản nên thử lại quá theo MSDN.

2

Trong môi trường OLTP chuẩn hóa truyền thống, NOLOCK là một mã nguồn và gần như chắc chắn không cần thiết trong một hệ thống được thiết kế phù hợp. Trong một mô hình chiều, tôi đã sử dụng rộng rãi NOLOCK để tránh khóa các bảng thực tế và kích thước rất lớn được điền dữ liệu thực tế sau này (và kích thước có thể đã hết hạn). Trong mô hình chiều, các sự kiện hoặc không bao giờ thay đổi hoặc không bao giờ thay đổi sau một thời điểm nhất định.Tương tự, bất kỳ tham số nào được tham chiếu cũng sẽ tĩnh, ví dụ, NOLOCK sẽ dừng hoạt động phân tích dài của bạn trên dữ liệu của ngày hôm qua từ việc chặn hết hạn thứ nguyên trong khi tải dữ liệu cho dữ liệu ngày nay.

11

Nếu ai đó nói rằng không có NOLOCK, ứng dụng của họ luôn bị bế tắc, thì có (nhiều khả năng) có vấn đề với truy vấn của họ. bế tắc có nghĩa là hai giao dịch không thể tiến hành vì tranh chấp tài nguyên và vấn đề không thể giải quyết được. Ví dụ:

Xem xét giao dịch A và B. Cả hai đều đang trên chuyến bay. Giao dịch A đã chèn một hàng vào bảng X và Giao dịch B đã chèn một hàng vào bảng Y, do đó, Giao dịch A có khóa độc quyền trên X và Giao dịch B có khóa độc quyền trên Y.

Hiện tại, Giao dịch A cần chạy SELECT đối với bảng Y và giao dịch B cần chạy một lệnh SELECT đối với bảng X.

Hai giao dịch bị bế tắc: Một tài nguyên cần Y và B cần tài nguyên X. Vì giao dịch không thể tiến hành cho đến khi giao dịch khác hoàn thành giải quyết: không yêu cầu giao dịch cho một nguồn lực có thể được satisified cho đến khi giao dịch khác phát hành khóa của nó trên tài nguyên trong tranh chấp (hoặc bằng ROLLBACK hoặc COMMIT, không quan trọng.)

SQL Server xác định tình huống này và chọn một giao dịch hoặc giao dịch khác với tư cách là nạn nhân bế tắc, hủy bỏ giao dịch đó và quay lại, để giao dịch khác tự do tiến hành hoàn thành có thể đoán trước.

Rối khóa hiếm gặp trong đời thực (IMHO). Một chính càn chúng bằng cách

  • đảm bảo rằng phạm vi giao dịch là càng nhỏ càng tốt, một cái gì đó SQL server không tự động (phạm vi giao dịch mặc định SQL Server là một tuyên bố duy nhất với một tiềm ẩn COMMIT), và
  • đảm bảo rằng các nguồn lực giao dịch truy cập trong cùng một trình tự. Trong ví dụ trên, nếu giao dịch A và B cả hai tài nguyên bị khóa X và Y trong cùng một chuỗi, sẽ không có bế tắc.

Timeouts

Đã hết thời gian, mặt khác, xảy ra khi một giao dịch vượt quá thời gian chờ đợi của nó và được cuộn lại do tranh chấp tài nguyên. Ví dụ, Giao dịch A cần tài nguyên X. Tài nguyên X bị khóa bởi Giao dịch B, do đó, Giao dịch A chờ khóa được giải phóng. Nếu khóa không được giải phóng trong thời gian hết hạn của truy vấn, giao dịch chờ đợi sẽ bị hủy và được khôi phục. Mỗi truy vấn có thời gian chờ truy vấn liên kết với nó (giá trị mặc định là 30 giây, tôi tin), sau thời gian giao dịch bị hủy bỏ và được khôi phục. Thời gian chờ truy vấn có thể được đặt thành 0 giây, trong trường hợp đó SQL Server sẽ cho phép truy vấn chờ đợi mãi mãi.

Đây có thể là những gì họ đang nói đến. Theo kinh nghiệm của tôi, thời gian chờ như thế thường xảy ra trong cơ sở dữ liệu lớn khi công việc hàng loạt đang cập nhật hàng nghìn và hàng nghìn bản ghi trong một giao dịch duy nhất, mặc dù chúng có thể xảy ra do giao dịch kéo dài (kết nối với cơ sở dữ liệu sản xuất của bạn trong Query Abalyzer, thực thi BEGIN GIAO DỊCH, cập nhật một hàng trong bảng thường xuyên truy vấn trong Trình phân tích truy vấn và đi ăn trưa mà không thực thi ROLLBACK hoặc COMMIT TRANSACTION và xem mất bao lâu để các DBA sản xuất đi vượn ** t trên bạn.Đừng hỏi tôi làm thế nào tôi biết điều này)

loại này thời gian chờ thường là những gì dẫn đến đổ ra SQL một cách hoàn hảo vô tội với tất cả các loại NOLOCK gợi ý

[TIP: nếu bạn sẽ làm điều đó, chỉ cần thực thi SET GIAO DIỆN BẠC ĐỌC ĐỌC ĐƯỢC CHẤP NHẬN là câu lệnh đầu tiên trong thủ tục lưu trữ của bạn và đã thực hiện với nó.]

Vấn đề với cách tiếp cận này (NOLOCK/READ UNCOMMITTED) là bạn có thể đọc dữ liệu không được cam kết từ giao dịch khác: không đầy đủ hoặc có thể được khôi phục sau, vì vậy tính toàn vẹn dữ liệu của bạn bị bắt buộc. Bạn có thể gửi một hóa đơn dựa trên dữ liệu có mức độ bogosity cao.

Quy tắc chung của tôi là người ta nên tránh sử dụng các gợi ý bảng càng sâu càng tốt. Hãy để SQL Server và trình tối ưu hóa truy vấn của nó thực hiện công việc của họ.

Cách đúng để tránh loại sự cố này là tránh loại giao dịch (ví dụ: chèn một triệu hàng tại một ngã rẽ) gây ra sự cố. Chiến lược khóa ẩn trong cơ sở dữ liệu quan hệ SQL được thiết kế xung quanh các giao dịch nhỏ của phạm vi ngắn. Khóa phải nhỏ trong phạm vi và thời lượng ngắn. Hãy nghĩ "nhân viên ngân hàng cập nhật tài khoản séc của ai đó bằng khoản tiền gửi." như trường hợp sử dụng cơ bản. Thiết kế các quy trình của bạn để làm việc trong mô hình đó và bạn sẽ hạnh phúc hơn nhiều theo cách 'tròn.

Thay vì chèn một triệu hàng trong một câu lệnh chèn mondo, hãy thực hiện công việc theo các đoạn độc lập và cam kết từng đoạn độc lập. Nếu hàng triệu hàng của bạn bị chết sau khi xử lý 999.000 hàng, tất cả công việc đã hoàn thành sẽ bị mất (chưa kể rằng rollback có thể là ab * tch, và bảng vẫn bị khóa trong quá trình rollback.) Nếu bạn chèn hàng triệu hàng của 1000 hàng mỗi, cam kết sau mỗi khối, bạn tránh tranh chấp khóa gây ra deadlocks, như ổ khóa sẽ được thu được và phát hành và mọi thứ sẽ tiếp tục di chuyển. Nếu một cái gì đó đi về phía nam trong khối 999 của 1000 hàng, và giao dịch bị hủy bỏ và quay trở lại, bạn vẫn nhận được 998.000 hàng được chèn vào; bạn chỉ mất 1000 hàng công việc. Khởi động lại/Thử lại dễ dàng hơn nhiều.

Ngoài ra, khóa leo thang xảy ra trong các giao dịch lớn. Đối với hiệu quả, ổ khóa leo thang đến phạm vi lớn hơn và lớn hơn khi số lượng khóa được tổ chức bằng cách tăng giao dịch. Nếu một giao dịch đơn lẻ chèn/cập nhật/xóa một hàng duy nhất trong một bảng, tôi sẽ nhận được một khóa hàng. Tiếp tục thực hiện điều đó và khi số lượng khóa hàng được giữ bởi giao dịch đó với bảng đó đạt giá trị ngưỡng, SQL Server sẽ báo cáo chiến lược khóa: các khóa hàng sẽ được hợp nhất và chuyển đổi thành khóa trang số nhỏ hơn, do đó tăng phạm vi các ổ khóa được giữ. Từ thời điểm đó trở đi, một chèn/xóa/cập nhật của một hàng sẽ khóa trang đó trong bảng. Khi số lượng khóa trang được giữ lên giá trị ngưỡng của nó, khóa trang sẽ được củng cố lại và chiến lược khóa sẽ chuyển sang khóa bảng: giao dịch hiện khóa toàn bộ bảng và không ai khác có thể chơi cho đến khi giao dịch cam kết hoặc quay lại.

Cho dù bạn có thể tránh việc sử dụng chức năng NOLOCK/READ UNCOMMITTED hoàn toàn phụ thuộc vào bản chất của các quy trình đánh cơ sở dữ liệu bên dưới (và văn hóa của tổ chức sở hữu nó).

Bản thân tôi, tôi cố gắng tránh sử dụng càng nhiều càng tốt.

Hy vọng điều này sẽ hữu ích.

+0

Cảm ơn! Tôi nghĩ rằng thêm thông tin tốt cho cuộc thảo luận. – Limey

1

Bạn chỉ nên sử dụng nolock trên bảng không thay đổi. Tất nhiên, điều này sẽ giống nhau khi đọc Ảnh chụp đã cam kết. Nếu không có ảnh chụp nhanh, bạn chỉ tiết kiệm thời gian cần thiết để áp dụng khóa được chia sẻ và sau đó loại bỏ nó, hầu hết các trường hợp là không cần thiết.

Đối với bảng thay đổi ... Không khóa không có nghĩa là nhận hàng trước khi giao dịch được thực hiện cập nhật tất cả các hàng của nó. Bạn có thể nhận được dữ liệu ma như các trang dữ liệu được chia, hoặc thậm chí là các trang chỉ mục được chia nhỏ. Hoặc không có dữ liệu. Điều đó một mình làm tôi sợ hãi, nhưng tôi nghĩ rằng có thể có nhiều kịch bản hơn, nơi bạn chỉ nhận được dữ liệu sai.

Tất nhiên, nolock để nhận được các ước tính sơ bộ hoặc chỉ cần kiểm tra trong một quy trình có thể là hợp lý.

Quy tắc cơ bản của ngón tay cái - nếu bạn quan tâm đến dữ liệu chút nào và dữ liệu đang thay đổi, thì không sử dụng NoLOCK.

+0

Noggins - nó không phải là dữ liệu cần phải tầm thường; nó là yêu cầu của dữ liệu. Tôi đưa ra hai ví dụ - ước tính, hoặc để có được một số loại ý tưởng mà bạn đang ở. Vì vậy, các dữ liệu/quá trình có thể được, và sẽ được, hoàn toàn cần thiết. Nhưng những trường hợp sử dụng cụ thể để đọc có thể làm như vậy với nolock vì bạn sẽ không sử dụng dữ liệu để thiết kế một nuke hay gì đó. Chỉ cần đăng ký. –

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