Thứ tự lưu trữ so với thứ tự kết quả


8

Đây là một câu hỏi phụ từ thứ tự Sắp xếp được chỉ định trong khóa chính, nhưng việc sắp xếp được thực hiện trên CHỌN .

@Catcall nói điều này về chủ đề của thứ tự lưu trữ (chỉ mục được nhóm) và thứ tự đầu ra

Rất nhiều người tin rằng một chỉ mục được nhóm đảm bảo một thứ tự sắp xếp trên đầu ra. Nhưng đó không phải là những gì nó làm; nó đảm bảo một thứ tự lưu trữ trên đĩa. Xem, ví dụ, bài blog này .

Tôi đã đọc bài đăng trên blog của Hugo Kornelis và hiểu rằng một chỉ mục không đảm bảo rằng máy chủ sql đọc các bản ghi theo một thứ tự cụ thể. Tuy nhiên, tôi có một thời gian khó chấp nhận rằng tôi không thể giả định điều này cho kịch bản của mình?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

Truy vấn ban đầu của tôi là:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Nhưng tôi đề nghị rằng tôi cũng có thể sử dụng cái này (đọc bên dưới để giải thích cho tôi):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Như bạn có thể thấy, các hàng trong bảng của tôi nhỏ (16byte) và tôi chỉ có một chỉ mục, một cụm. Trong kịch bản của tôi, bảng bao gồm 100.000.000 bản ghi tại thời điểm này (và điều này rất có thể sẽ tăng gấp 10 lần).

Khi máy chủ cơ sở dữ liệu truy vấn bảng này, nó có hai cách để tìm các hàng của tôi, hoặc nó tìm khóa chính và do đó đọc và trả về các giá trị của tôi trong desc. thứ tự của Ngày, hoặc nó phải thực hiện quét toàn bộ bảng. Kết luận của tôi là quét toàn bộ bảng trên tất cả các bản ghi đó sẽ quá chậm và do đó máy chủ cơ sở dữ liệu sẽ luôn tìm kiếm bảng thông qua khóa chính của nó và do đó trả về các giá trị được sắp xếp theoDate DESC


2
Tại sao bạn muốn có thể dựa vào giả định này rất tệ? Tại sao bạn không đặt ORDER BYnó ở đó, sau đó bạn biết bạn có thể dựa vào nó. Xem # 3 tại đây
Aaron Bertrand

Vì 2 lý do, sự tò mò và vì ORDER BYmệnh đề là một thành tích lớn đối với tôi (đọc câu hỏi khác để biết thêm). Tôi có một giải pháp hoạt động ngay bây giờ, nhưng nó sẽ không giữ được khi nào và nếu lưu lượng truy cập của tôi tăng lên.
m__

1
ĐẶT HÀNG B NOTNG không nên là một cú hích hiệu suất nếu bạn đang dựa vào thứ tự mà bạn nhìn thấy mà không có thứ tự bởi - điều đó không có ý nghĩa với tôi.
Aaron Bertrand

4
Các Điều duy nhấtđảm bảo cho kết quả thiết lập trật tự là một ORDER BYđiều khoản trong truy vấn của bạn. Điều này đúng với SQL Server , Oracle , MySQL và bất kỳ RDBMS nào khác mà bạn có thể nghĩ đến. Hãy thử bất cứ điều gì khác và bạn đang thiết lập cho mình một cốc FAIL bất ngờ.
Nick Chammas

Câu trả lời:


15

Hãy để tôi giải thích lý do tại sao bạn không nên làm điều đó, tại sao bạn không bao giờ nên cho rằng một sản phẩm SQL sẽ trả về một kết quả được đặt theo một thứ tự cụ thể, trừ khi bạn chỉ định như vậy, bất kỳ chỉ số nào - cụm hoặc cụm, B-cây hoặc Cây R hoặc cây kd hoặc cây fractal hoặc bất kỳ chỉ số kỳ lạ nào khác mà DBMS đang sử dụng.


Truy vấn ban đầu của bạn yêu cầu DBMS tìm kiếm SensorValuesbảng, tìm các hàng khớp với 3 điều kiện, sắp xếp các hàng đó bằng cách Dategiảm dần, chỉ giữ hàng đầu tiên trong số đó và - cuối cùng - chỉ chọn và trả về SensorValuecột.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

Đây là những đơn đặt hàng rất cụ thể mà bạn đã đưa ra cho DBMS và kết quả rất có thể sẽ giống nhau mỗi khi bạn chạy truy vấn (có thể có thể không, nếu bạn có nhiều hơn một hàng khớp với các điều kiện và có cùng điều kiện tối đa Datenhưng khác nhau SensorValuenhưng hãy giả sử cho phần còn lại của cuộc trò chuyện rằng không có hàng nào như vậy tồn tại trong bảng của bạn).

DBMS có phải làm điều này không, để chạy truy vấn này, cách chính xác mà tôi mô tả ở trên? Không, tất nhiên là không và bạn biết điều đó. Nó có thể không đọc bảng nhưng đọc từ một chỉ mục. Hoặc nó có thể sử dụng hai chỉ mục nếu nó nghĩ rằng nó tốt hơn (nhanh hơn). Hoặc ba. Hoặc nó có thể sử dụng kết quả được lưu trong bộ nhớ cache (không phải SQL Server mà là các kết quả truy vấn bộ đệm DBMS khác). Hoặc nó có thể sử dụng thực thi song song một lần và không phải lần sau nó chạy. Hoặc ... (thêm bất kỳ tính năng nào khác ảnh hưởng đến kế hoạch thực hiện và thực hiện).

Điều được đảm bảo là nó sẽ trả về cùng một kết quả, mỗi khi bạn chạy nó - miễn là không có hàng nào được chèn, xóa hoặc cập nhật.


Bây giờ hãy xem đề xuất của bạn nói gì:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Truy vấn này yêu cầu DBMS tìm kiếm SensorValuesbảng, tìm các hàng khớp với 3 điều kiện, sắp xếp các hàng đó bằng cách Dategiảm dần, không quan tâm đến thứ tự, chỉ giữ một hàng và - cuối cùng - chỉ chọn và trả về SensorValuecột.

Vì vậy, về cơ bản, nó nói giống như kết quả đầu tiên, ngoại trừ việc nó nói rằng bạn chỉ muốn một kết quả phù hợp với điều kiện và bạn không quan tâm đến kết quả nào .

Bây giờ, chúng ta có thể giả định rằng nó sẽ luôn cho kết quả tương tự vì chỉ số được nhóm không?
- Nếu nó sử dụng chỉ số cụm này mỗi lần, có.

Nhưng nó sẽ sử dụng nó?
- Không.

Tại sao không?
- Beacuse nó có thể. Trình tối ưu hóa truy vấn có thể tự do chọn đường dẫn thực thi mỗi khi chạy câu lệnh. Bất cứ con đường nào nó thấy phù hợp tại thời điểm đó cho tuyên bố đó.

Nhưng không phải sử dụng chỉ mục cụm là cách tốt nhất / nhanh nhất để có kết quả?
- Không, không phải lúc nào. Đây có thể là lần đầu tiên bạn chạy truy vấn. Lần thứ hai, nó có thể sử dụng kết quả được lưu trong bộ nhớ cache (nếu DBMS có tính năng như vậy, không phải SQL Server * ). Lần thứ 1000 kết quả có thể đã bị xóa khỏi bộ đệm và kết quả khác có thể tồn tại ở đó. Giả sử, bạn đã thực hiện truy vấn này ngay trước đó:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

và kết quả được lưu trong bộ nhớ cache (từ truy vấn trên) là một kết quả khác, vẫn phù hợp với điều kiện của bạn nhưng không phải là kết quả đầu tiên trong thứ tự (muốn) của bạn. Và bạn đã nói với DBMS không quan tâm đến thứ tự.

OK, vậy chỉ bộ nhớ cache có thể ảnh hưởng đến điều này?
- Không, nhiều thứ khác nữa.

  • các chỉ mục khác đã được xem xét, tại thời điểm đó bởi DBMS là tốt hơn cho truy vấn này.
  • một nhà phát triển đã thay đổi hoặc loại bỏ hoàn toàn chỉ mục cụm này mà bạn có.
  • bạn hoặc một số nhà phát triển khác đã thêm một chỉ mục khác mà trình tối ưu hóa quyết định sử dụng hiệu quả hơn so với CI.
  • bạn đã cập nhật lên phiên bản mới và trình tối ưu hóa mới có một lỗi nhỏ hoặc thay đổi cách xếp hạng và chọn kế hoạch thực hiện.
  • số liệu thống kê đã được cập nhật.
  • thực hiện song song được chọn thay thế.

*: SQL Server không lưu trữ kết quả truy vấn nhưng Phiên bản doanh nghiệp có tính năng Quét nâng cao tương tự như bạn có thể nhận được các kết quả khác nhau do các truy vấn đồng thời. Không chắc chắn chính xác khi điều này đá mặc dù. (thnx @Martin Smith cho tiền boa.)


Tôi hy vọng bạn tin chắc rằng bạn không bao giờ nên tin rằng một truy vấn SQL sẽ trả về kết quả theo một thứ tự cụ thể, trừ khi bạn chỉ định như vậy. Và không bao giờ sử dụng TOP (n)mà không có ORDER BY, trừ khi tất nhiên bạn chỉ muốn n hàng trong kết quả và bạn không quan tâm cái nào được trả về.


2
SQL Server Enterprise Edition không có tính năng Quét nâng cao tương tự như bạn có thể nhận được các kết quả khác nhau do các truy vấn đồng thời. Không chắc chắn chính xác khi điều này đá mặc dù.
Martin Smith

1
Một điều khác có khả năng "ngẫu nhiên hóa" thứ tự kết quả (ngay cả khi truy vấn rõ ràng được điều khiển bởi một chỉ mục được đặt hàng) là song song. Tôi thấy một ứng dụng đang chạy SQL bị hỏng bắt đầu hoạt động kém sau khi kích hoạt tính năng song song tự động (không phải SQL Server, nhưng tôi đoán cũng có thể áp dụng ở đó).
Mat
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.