Phạm vi nối lại tìm kiếm trên chỉ số tổng hợp nullable?


14

Đố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 

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


FWIW: Nếu cột Ađược tạo NOT NULLvà 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ập mô tả hình ảnh ở đây

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?


Lỗi của tôi. Tôi quên rằng NULLcá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
ypercubeᵀᴹ

Có Oracle là khác tôi tin.
Martin Smith


@ypercube - SQL Server chỉ cung cấp một lần quét theo thứ tự cho điều không may đó để đọc lại tất cả các hàng đã được ứng dụng xử lý (đọc logic 2015). Nó không tìm kiếm khóa đầu tiên của(NULL, 1000 )
Martin Smith

Với 2 điều kiện khác nhau, cho dù @Acó 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
ypercubeᵀᴹ

Câu trả lời:


21

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?

Một giải pháp yêu thích của tôi là sử dụng một APIcon trỏ:

SET NOCOUNT ON;
SET STATISTICS IO ON;

DECLARE 
    @cur integer,
    -- FAST_FORWARD, AUTO_FETCH, AUTO_CLOSE, CHECK_ACCEPTED_TYPES, FAST_FORWARD_ACCEPTABLE
    @scrollopt integer = 16 | 8192 | 16384 | 32768 | 1048576,
    -- READ_ONLY, CHECK_ACCEPTED_OPTS, READ_ONLY_ACCEPTABLE
    @ccopt integer = 1 | 32768 | 65536, 
    @rowcount integer = 1000,
    @rc integer;

-- Open the cursor and return (up to) the first 1000 rows
EXECUTE @rc = sys.sp_cursoropen
    @cur OUTPUT,
    N'
    SELECT A, B, C
    FROM T
    ORDER BY A, B;
    ',
    @scrollopt OUTPUT,
    @ccopt OUTPUT,
    @rowcount OUTPUT;

IF @rc <> 16 -- FastForward cursor automatically closed
BEGIN
    -- Name the cursor so we can use CURSOR_STATUS
    EXECUTE sys.sp_cursoroption
        @cur, 
        2, 
        'MyCursorName';

    -- Until the cursor auto-closes
    WHILE CURSOR_STATUS('global', 'MyCursorName') = 1
    BEGIN
        EXECUTE sys.sp_cursorfetch
            @cur,
            2,
            0,
            1000;
    END;
END;

SET STATISTICS IO OFF;

Chiến lược tổng thể là một lần quét duy nhất ghi nhớ vị trí của nó giữa các cuộc gọi. Sử dụng một APIcon trỏ có nghĩa là chúng ta có thể trả về một khối các hàng thay vì một hàng tại một thời điểm như trường hợp với một T-SQLcon trỏ:

Kế hoạch thực hiện

Đầu STATISTICS IOra là:

Table 'T'. Scan count 1, logical reads 1011, physical reads 0, read-ahead reads 0
Table 'T'. Scan count 1, logical reads 1001, physical reads 0, read-ahead reads 0
Table 'T'. Scan count 1, logical reads 516, physical reads 0, read-ahead reads 0
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.