Đối với dữ liệu ví dụ và lược đồ sau
CREATE TABLE T
(
A INT NULL,
B INT NOT NULL IDENTITY,
C CHAR(8000) NULL,
UNIQUE CLUSTERED (A, B)
)
INSERT INTO T
(A)
SELECT NULLIF(( ( ROW_NUMBER() OVER (ORDER BY @@SPID) - 1 ) / 1003 ), 0)
FROM master..spt_values
Một ứng dụng đang xử lý các hàng từ bảng này theo thứ tự chỉ mục được nhóm trong 1.000 khối hàng.
1.000 hàng đầu tiên được lấy từ truy vấn sau.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
Hàng cuối cùng của bộ đó là bên dưới
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
Có cách nào để viết một truy vấn chỉ tìm kiếm vào khóa chỉ mục tổng hợp đó và sau đó theo nó để lấy đoạn tiếp theo của 1000 hàng không?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
Số lần đọc thấp nhất mà tôi đã quản lý để đạt được cho đến nay là 1020 nhưng truy vấn dường như quá phức tạp. Có một cách đơn giản hơn bằng hoặc hiệu quả tốt hơn? Có lẽ một người quản lý để làm tất cả trong một phạm vi tìm kiếm?
DECLARE @A INT = NULL, @B INT = 1000
;WITH UnProcessed
AS (SELECT *
FROM T
WHERE ( EXISTS(SELECT A
INTERSECT
SELECT @A)
AND B > @B )
UNION ALL
SELECT *
FROM T
WHERE @A IS NULL AND A IS NOT NULL
UNION ALL
SELECT *
FROM T
WHERE A > @A
)
SELECT TOP 1000 *
FROM UnProcessed
ORDER BY A,
B
FWIW: Nếu cột A
được tạo NOT NULL
và giá trị sentinel -1
được sử dụng thay vì kế hoạch thực hiện tương đương chắc chắn trông đơn giản hơn
Nhưng toán tử tìm kiếm duy nhất trong kế hoạch vẫn thực hiện hai lần tìm kiếm thay vì thu gọn nó thành một phạm vi tiếp giáp duy nhất và các lần đọc logic giống nhau, vì vậy tôi nghi ngờ rằng có lẽ điều này sẽ tốt như nó sẽ có được?
(NULL, 1000 )
@A
có null hay không, có vẻ như nó không thực hiện quét. Nhưng tôi không thể hiểu nếu các kế hoạch tốt hơn truy vấn của bạn. Fiddle-2
NULL
các giá trị luôn luôn là đầu tiên. (giả sử ngược lại.) Điều kiện chính xác tại Fiddle