Các ví dụ trong câu hỏi không hoàn toàn tạo ra kết quả giống nhau ( OFFSET
ví dụ này có lỗi do lỗi một). Các hình thức cập nhật dưới đây khắc phục vấn đề đó, loại bỏ sắp xếp bổ sung cho ROW_NUMBER
trường hợp và sử dụng các biến để làm cho giải pháp tổng quát hơn:
DECLARE
@PageSize bigint = 10,
@PageNumber integer = 3;
WITH Numbered AS
(
SELECT TOP ((@PageNumber + 1) * @PageSize)
o.*,
rn = ROW_NUMBER() OVER (
ORDER BY o.[object_id])
FROM #objects AS o
ORDER BY
o.[object_id]
)
SELECT
x.name,
x.[object_id],
x.principal_id,
x.[schema_id],
x.parent_object_id,
x.[type],
x.type_desc,
x.create_date,
x.modify_date,
x.is_ms_shipped,
x.is_published,
x.is_schema_published
FROM Numbered AS x
WHERE
x.rn >= @PageNumber * @PageSize
AND x.rn < ((@PageNumber + 1) * @PageSize)
ORDER BY
x.[object_id];
SELECT
o.name,
o.[object_id],
o.principal_id,
o.[schema_id],
o.parent_object_id,
o.[type],
o.type_desc,
o.create_date,
o.modify_date,
o.is_ms_shipped,
o.is_published,
o.is_schema_published
FROM #objects AS o
ORDER BY
o.[object_id]
OFFSET @PageNumber * @PageSize - 1 ROWS
FETCH NEXT @PageSize ROWS ONLY;
Các ROW_NUMBER
kế hoạch có chi phí ước tính của 0.0197935 :
Các OFFSET
kế hoạch có chi phí ước tính của 0.0196955 :
Đó là tiết kiệm 0,000098 đơn vị chi phí ước tính (mặc dù OFFSET
kế hoạch sẽ yêu cầu các nhà khai thác bổ sung nếu bạn muốn trả về một số hàng cho mỗi hàng). Các OFFSET
kế hoạch vẫn sẽ hơi rẻ hơn, nói chung, nhưng hãy nhớ rằng chi phí ước tính là chính xác điều đó - thử nghiệm thực vẫn còn cần thiết. Phần lớn chi phí trong cả hai gói là chi phí của toàn bộ bộ đầu vào, vì vậy các chỉ mục hữu ích sẽ có lợi cho cả hai giải pháp.
Khi các giá trị bằng chữ không đổi được sử dụng (ví dụ OFFSET 30
trong ví dụ ban đầu), trình tối ưu hóa có thể sử dụng Sắp xếp TopN thay vì sắp xếp đầy đủ theo sau là Top. Khi các hàng cần từ Sắp xếp TopN là một chữ không đổi và <= 100 (tổng OFFSET
và FETCH
), công cụ thực thi có thể sử dụng thuật toán sắp xếp khác có thể thực hiện nhanh hơn so với sắp xếp TopN tổng quát. Tất cả ba trường hợp có đặc điểm hiệu suất tổng thể khác nhau.
Về lý do tại sao trình tối ưu hóa không tự động chuyển đổi ROW_NUMBER
mẫu cú pháp để sử dụng OFFSET
, có một số lý do:
- Hầu như không thể viết một biến đổi phù hợp với tất cả các sử dụng hiện có
- Có một số truy vấn phân trang tự động chuyển đổi và không có truy vấn khác có thể gây nhầm lẫn
- Các
OFFSET
kế hoạch không đảm bảo được tốt hơn trong mọi trường hợp
Một ví dụ cho điểm thứ ba ở trên xảy ra khi bộ phân trang khá rộng. Có thể hiệu quả hơn nhiều khi tìm kiếm các khóa cần thiết bằng cách sử dụng chỉ mục không bao gồm và tra cứu thủ công so với chỉ mục được nhóm so với quét chỉ mục bằng OFFSET
hoặc ROW_NUMBER
. Có nhiều vấn đề cần xem xét nếu ứng dụng phân trang cần biết tổng số có bao nhiêu hàng hoặc trang. Có một cuộc thảo luận tốt khác về giá trị tương đối của các phương pháp 'tìm kiếm chính' và 'bù đắp' ở đây .
Nhìn chung, có lẽ tốt hơn là mọi người đưa ra quyết định có căn cứ để thay đổi truy vấn phân trang của họ để sử dụng OFFSET
, nếu phù hợp, sau khi thử nghiệm kỹ lưỡng.