Phân trang trong SQL Server


17

Tôi có một cơ sở dữ liệu rất lớn, khoảng 100 GB. Tôi đang thực hiện truy vấn:

select * from <table_name>;

và tôi muốn chỉ hiển thị các hàng thứ 100 đến 200.

Tôi muốn hiểu làm thế nào điều này xảy ra trong nội bộ. Cơ sở dữ liệu có tìm nạp tất cả các bản ghi từ đĩa vào bộ nhớ và gửi lại các hàng thứ 100 đến 400 cho máy khách truy vấn không? Hoặc có tồn tại bất kỳ cơ chế nào, để chỉ những bản ghi đó (thứ 100 -200) được tìm nạp từ cơ sở dữ liệu - bằng cách sử dụng cơ chế lập chỉ mục như cây B, v.v.?

Tôi thấy rằng điều này có liên quan đến khái niệm phân trang, nhưng tôi không thể tìm thấy chính xác làm thế nào nó xảy ra trong nội bộ ở cấp cơ sở dữ liệu.

Câu trả lời:


37

Trong truy vấn bạn đã đăng:

select * from <table_name>;

Không có thứ gọi là hàng thứ 100-200, vì bạn không chỉ định ĐẶT HÀNG B .NG. Đơn hàng không được đảm bảo trừ khi bạn bao gồm ĐẶT HÀNG B forNG vì nhiều lý do thú vị, nhưng đó không thực sự là vấn đề ở đây.

Vì vậy, để minh họa quan điểm của bạn, hãy sử dụng bảng - Tôi sẽ sử dụng bảng Người dùng từ kết xuất dữ liệu Stack Overflow và chạy truy vấn này:

SELECT * FROM dbo.Users ORDER BY DisplayName;

Theo mặc định, không có chỉ mục trên trường DisplayName, vì vậy SQL Server phải quét toàn bộ bảng, sau đó sắp xếp nó theo DisplayName. Đây là kế hoạch thực hiện :

Quét chỉ mục cụm với một loại

Nó không đẹp - đó là rất nhiều công việc, với chi phí phụ ước tính khoảng 30k. (Bạn có thể thấy nó bằng cách di chuột qua toán tử đã chọn tại PasteThePlan.) Vậy điều gì xảy ra nếu chúng ta chỉ muốn các hàng 100-200? Chúng tôi có thể sử dụng cú pháp này trong SQL Server 2012+:

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

Kế hoạch thực hiện trên đó cũng khá xấu xí:

Quét chỉ mục cụm với một loại và đầu

SQL Server vẫn đang quét toàn bộ bảng để xây dựng danh sách được sắp xếp chỉ để cung cấp cho bạn các hàng 100-200 của bạn và chi phí vẫn khoảng 30k. Thậm chí tệ hơn, toàn bộ danh sách này sẽ được xây dựng lại mỗi khi truy vấn của bạn chạy (vì sau tất cả, ai đó có thể đã thay đổi DisplayName của họ.)

Để làm cho nó đi nhanh hơn, chúng ta có thể tạo một chỉ mục không bao gồm trên DisplayName, một bản sao của bảng của chúng tôi, được sắp xếp theo trường cụ thể đó:

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

Với chỉ mục đó, kế hoạch thực hiện truy vấn của chúng tôi hiện tìm kiếm chỉ mục:

Tìm kiếm chỉ mục và tra cứu chính

Truy vấn kết thúc ngay lập tức và có chi phí phụ ước tính chỉ 0,66 (trái ngược với 30k).

Tóm lại, nếu bạn sắp xếp dữ liệu theo cách hỗ trợ các truy vấn bạn thường chạy, thì có, SQL Server có thể sử dụng các phím tắt để truy vấn của bạn nhanh hơn. Mặt khác, nếu tất cả những gì bạn có là đống hoặc chỉ mục cụm, bạn bị vặn.


"Theo mặc định, không có chỉ mục trên trường DisplayName, vì vậy SQL Server phải quét toàn bộ bảng, sau đó sắp xếp nó theo DisplayName." Xin lỗi nếu đây là một câu hỏi rất cơ bản - trong trường hợp tôi trích dẫn từ câu trả lời của bạn, Khi bạn nói "Quét toàn bộ bảng", điều đó có nghĩa là tất cả dữ liệu được đưa vào bộ nhớ và được sắp xếp (trông không đúng cách)?
AV94

Từ câu trả lời của bạn, tôi hiểu rằng nếu trường được lập chỉ mục, thì việc thực hiện các truy vấn như - lấy hàng thứ 100 đến 200 rất hiệu quả vì SQL tìm đến chỉ mục (cây B, v.v.) và trực tiếp đi đến điểm đó (hàng thứ 100). Bạn có thể vui lòng cho tôi biết nếu điều này là hiểu đúng?
AV94

@AnilVedala về câu hỏi đầu tiên của bạn - vâng, dữ liệu phải được sắp xếp. Làm thế nào khác một cơ sở dữ liệu có thể thực hiện điều đó với một danh sách chưa sắp xếp?
Brent Ozar

1
@AnilVedala về câu hỏi thứ hai của bạn - đó là nơi kế hoạch thực hiện cuối cùng tôi đưa cho bạn. (Nếu bạn đang hỏi về cách đọc kế hoạch thực hiện, hãy lấy cuốn sách Kế hoạch thực hiện của Grant Fritchey.)
Brent Ozar

15

Cũng giống như một bổ sung cho câu trả lời của Brent khi sử dụng chỉ mục không che để tránh sắp xếp, có một vấn đề tiềm ẩn với các số trang sau có thể được nhìn thấy khi chạy bên dưới

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

Kế hoạch thực hiện cho thấy việc tra cứu đã được thực hiện 100.100 lần mặc dù tất cả trừ 100 hàng sau đó được toán tử TOP lọc ra.

nhập mô tả hình ảnh ở đây

Điều này có thể được giảm nhẹ bằng cách sử dụng mẫu dưới đây

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

Điều này lọc ra tất cả ngoại trừ 100 hàng cuối cùng trước khi thực hiện tra cứu có thể có tác động đáng kể đến tốc độ cho các giá trị bù lớn.

nhập mô tả hình ảnh ở đây


3

Nó thực sự phụ thuộc vào cách bạn triển khai phân trang trong truy vấn của bạn, bản chất của dữ liệu và cách hệ thống của bạn được cấu hình. Khá an toàn để nói rằng SQL Server sẽ cố gắng trả lại dữ liệu của bạn bằng cách sử dụng những gì nó cảm thấy là ít nỗ lực nhất có thể. Nếu bạn không có thứ tự sắp xếp rõ ràng, lọc, nhóm hoặc bất kỳ cửa sổ nào thì SQL Server có thể tối ưu hóa kế hoạch truy vấn sao cho nó có thể trả về chỉ các trang từ đĩa chứa dữ liệu theo yêu cầu của bạn - hoặc thậm chí tốt hơn, trực tiếp từ bể đệm. Ngay khi bạn bắt đầu thay đổi truy vấn để bao gồm sắp xếp, nhóm, cửa sổ và lọc thì nó bắt đầu trở nên phức tạp.

Có một bài viết rất hay về Hiệu suất SQL ở đây đi sâu vào một số chi tiết về các phương pháp phân trang khác nhau và cách chúng ảnh hưởng đến kế hoạch truy vấn. Tôi đặc biệt khuyên bạn nên đọc nó và sau đó thử một số phương pháp khác nhau mà họ chỉ ra và xem kế hoạch truy vấn nào được chọn trên hệ thống của riêng bạn.

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.