Aşağıdaki şema ve örnek veriler için
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
Bir uygulama, bu tablodaki satırları 1000 satırlık kümeler halinde kümelenmiş dizin düzeninde işliyor.
İlk 1000 satır aşağıdaki sorgudan alınır.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
Bu setin son satırı aşağıda
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
Sadece bu bileşik dizin anahtarını arar ve sonra 1000 satır sonraki yığın almak için takip bir sorgu yazmak için herhangi bir yolu var mı?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
Şimdiye kadar elde ettiğim en düşük okuma sayısı 1020'dir, ancak sorgu çok kıvrımlı görünüyor. Eşit veya daha iyi verimlilik için daha basit bir yol var mı? Belki de hepsini tek bir aralıkta yapmayı başarabilen biri?
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: Sütun A
yapılırsa NOT NULL
ve bir sentinel değeri -1
kullanılırsa, bunun yerine eşdeğer yürütme planı kesinlikle daha basit görünür
Ancak plandaki tek arama operatörü hala tek bir bitişik aralığa daraltmak yerine iki arama gerçekleştirir ve mantıksal okumalar aynıdır, bu yüzden belki de bu kadar iyi olacağından şüpheleniyorum?
(NULL, 1000 )
@A
boş olup olmamasına bağlı olarak, tarama yapmıyor gibi görünüyor. Ama planların sorgunuzdan daha iyi olup olmadığını anlayamıyorum. Fiddle-2
NULL
Değerlerin her zaman ilk olduğunu unuttum . Düzeltilmiş koşulu (. aksini farz) Fiddle