Gợi ý NOLOCK thay đổi thứ tự của hồ sơ trả lại


10

Có một chỉ mục được nhóm trên một Clienttrường bảng LastName.

Khi tôi chỉ cần đổ tất cả các bản ghi từ bảng, chúng sẽ xuất hiện theo thứ tự bảng chữ cái trừ khi (nolock)gợi ý được sử dụng như trong truy vấn trong câu hỏi. Đó là gợi ý thay đổi thứ tự của hồ sơ. Có nên không? Tôi khẳng định rằng không có phiên nào khác có giao dịch mở với các thay đổi đối với bảng đó (ít nhất sp_who2là không hiển thị cho tôi bất kỳ).

Làm thế nào có thể giải thích sự khác biệt trong thứ tự?

Thông tin bổ sung được lấy từ ý kiến:

  1. Không có thứ tự bởi. Chỉ số không cụm nên thực thi lệnh?

  2. Các truy vấn vẫn trả về thứ tự khác nhau ngay cả khi sử dụng một gợi ý chỉ mục chỉ định một chỉ mục được nhóm. Họ nên? Tôi tự hỏi tại sao nolockthay đổi thứ tự của các hồ sơ trả lại mà không có sự thay đổi rõ ràng của các kế hoạch.

  3. Tôi đã thực hiện WinDiff trên chúng - tương tự ngoại trừ [the] (nolock)[gợi ý truy vấn].


21
Gợi ý không thay đổi thứ tự - vì không có thứ tự nào có thể thay đổi
a_horse_with_no_name

Câu trả lời:


47

Sự xuất hiện của một tập kết quả được đặt hàng, không có ORDER BYmệnh đề, thường là kết quả của quá trình quét lấy các hàng theo thứ tự chỉ mục. Một lý do tại sao quét theo thứ tự thường được chọn theo READ COMMITTEDmức cô lập mặc định là vì nó làm giảm khả năng xảy ra sự bất thường đồng thời không mong muốn như gặp phải cùng một hàng nhiều lần hoặc bỏ qua một số hàng. Đây là chi tiết ở một số nơi, bao gồm trong loạt bài viết về mức độ cô lập.

Với một NOLOCKgợi ý bảng, hành vi này được nới lỏng và việc truy cập vào bảng được thực hiện dưới READ UNCOMMITTEDmức cô lập khoan dung hơn , có thể quét dữ liệu theo thứ tự phân bổ thay vì thứ tự chỉ mục. Như được mô tả trong liên kết đó, quyết định về việc sử dụng quét theo thứ tự cấp phát hoặc thứ tự chỉ mục được dành cho công cụ lưu trữ. Lựa chọn này có thể thay đổi giữa các lần thực hiện mà không thay đổi trong kế hoạch truy vấn .

Điều này nghe có vẻ rất trừu tượng, nhưng có thể được chứng minh dễ dàng hơn với một số truy vấn sử dụng các chức năng không có giấy tờ đối với cơ sở dữ liệu AdventureWorks2012 .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

Kết quả truy vấn

Các truy vấn được mượn với sửa đổi nhỏ từ Paul White .

Cuối cùng, để rõ ràng, câu trả lời này là về sự xuất hiện của một tập kết quả được đặt hàng. Không có thứ tự trình bày được đảm bảo mà không có cấp cao nhất ORDER BY.

Quét theo thứ tự phân bổ có thể xảy ra trong nhiều trường hợp khác, chẳng hạn như khi có được khóa cấp bảng hoặc cơ sở dữ liệu ở chế độ chỉ đọc. Tính song song cũng có thể ảnh hưởng đến thứ tự dữ liệu được trả về. Điểm quan trọng là không có ORDER BY, dữ liệu thứ tự được trả về có thể thay đổi theo thời gian theo thiết kế.


7
Đẹp, cụ thể hơn nhiều so với nỗ lực không được đánh giá cao của tôi. Mấu chốt là trong hai đoạn cuối của bạn, tất nhiên. "Tại sao" không thực sự quan trọng cuối cùng. Có lẽ bạn sẽ gặp may mắn hơn với hợp âm đó hơn tôi đã làm.
Aaron Bertrand

11

James giải thích độc đáo cách thức hoạt động của nó, nhưng tôi chỉ muốn nhắc lại một điều: trừ khi bạn sử dụng chức năng đặt hàng, thứ tự các hàng trong tập kết quả không được xác định . Nếu bạn cần một đơn đặt hàng nhất định, hãy sử dụng một order bymệnh đề rõ ràng - nếu bạn không chỉ định nó, về cơ bản bạn sẽ nói "Tôi hoàn toàn không quan tâm đến đơn hàng", chứ không phải "Đặt hàng theo chỉ mục được nhóm".


11

Khi tôi chỉ cần đổ tất cả các bản ghi từ bảng

... Sau đó, bạn không nên mong đợi bất kỳ thứ tự. Trong thực tế, cùng một truy vấn chạy nhiều lần có thể quay lại theo một thứ tự khác mà không cần cảnh báo. Lý do là hai truy vấn của bạn - đó là các truy vấn "khác nhau" rất có thể là do văn bản truy vấn khác nhau, không phải do gợi ý - có các kế hoạch thực hiện khác nhau (và sự khác biệt có thể tinh tế, chẳng hạn như một trình vòng lặp trông giống nhau trong cả hai kế hoạch, nhưng ordered: truechỉ có một hoặc một số lượng lớn các hàng ước tính khác nhau vì một hàng được biên dịch trước khi thay đổi dữ liệu lớn). Nó cũng có thể là một quét thứ tự phân bổ đang được thực hiện, như James đã phác thảo đúng trong câu trả lời của mình.

Trong mọi trường hợp, vì bạn đang chạy một truy vấn mà không có ORDER BY, SQL Server cho rằng bạn không quan tâm đến thứ tự, vì vậy hãy tắt và xác định cách hiệu quả nhất để trả về các hàng (nó không quan tâm đến thứ tự nếu bạn không ).

Hãy để tôi làm cho điều này rất rõ ràng:

Nếu bạn muốn hoặc mong đợi một đơn hàng nhất định, hãy thêm mệnh đề ORDER BY

Điều này đã được đưa ra trước đây:

Và tôi đã viết về nó:

Dưới đây là một trích dẫn từ sau nhắc lại những gì tôi đã nói để giải quyết nhận xét của bạn về việc sử dụng một gợi ý chỉ mục thay vì một ORDER BYmệnh đề:

Ngay cả trong trường hợp chỉ mục được gợi ý, chỉ mục sẽ được sử dụng (nếu có thể, một lỗi khác trong hầu hết các trường hợp), nhưng chỉ vì sử dụng chỉ mục không có nghĩa là kết quả sẽ được trả về được sắp xếp theo (các) khóa trong chỉ số đó. Bạn vẫn cần một ORDER BYđể đảm bảo sắp xếp theo (các) khóa chỉ mục.

Conor Cickyham - một anh chàng khá thông minh, chịu trách nhiệm trực tiếp cho hầu hết những gì SQL Server làm khi xử lý truy vấn cho bạn - cũng đã viết về nó ở đây:

Vui lòng đọc một số và sau đó thêm một ORDER BYmệnh đề vào các truy vấn của bạn trước khi phàn nàn về cách sắp xếp khác nhau hoặc bất 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.