Untuk skema dan contoh data berikut
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
Aplikasi sedang memproses baris dari tabel ini dalam urutan indeks berkerumun dalam 1.000 potongan baris.
1.000 baris pertama diambil dari kueri berikut.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
Baris terakhir dari set itu adalah di bawah ini
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
Apakah ada cara untuk menulis kueri yang hanya mencari kunci indeks komposit dan kemudian mengikutinya untuk mengambil potongan 1000 baris berikutnya?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
Jumlah pembacaan terendah yang berhasil saya dapatkan sejauh ini adalah 1020 tetapi kueri tampaknya terlalu berbelit-belit. Apakah ada cara yang lebih sederhana untuk efisiensi yang sama atau lebih baik? Mungkin yang berhasil melakukan semuanya dalam satu rentang mencari?
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: Jika kolom A
dibuat NOT NULL
dan nilai sentinel -1
digunakan sebagai gantinya, rencana eksekusi yang setara tentu terlihat lebih sederhana
Tetapi operator pencarian tunggal dalam rencana tersebut masih melakukan dua upaya daripada meruntuhkannya menjadi satu rentang yang berdekatan dan pembacaan logisnya hampir sama, jadi saya curiga bahwa mungkin ini cukup baik seperti yang akan didapat?
(NULL, 1000 )
@A
null atau tidak, sepertinya tidak melakukan pemindaian. Tapi saya tidak bisa mengerti jika rencana lebih baik daripada permintaan Anda. Fiddle-2
NULL
nilai selalu yang pertama. (diasumsikan sebaliknya.) Kondisi terkoreksi di Fiddle