Per il seguente schema e dati di esempio
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
Un'applicazione sta elaborando le righe da questa tabella in ordine di indice cluster in blocchi di 1.000 righe.
Le prime 1.000 righe vengono recuperate dalla query seguente.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
L'ultima riga di quel set è sotto
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
Esiste un modo per scrivere una query che cerca solo quella chiave di indice composita e quindi la segue per recuperare il blocco successivo di 1000 righe?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
Il numero più basso di letture che sono riuscito a ottenere finora è 1020 ma la query sembra troppo contorta. Esiste un modo più semplice di uguale o migliore efficienza? Forse uno che riesce a fare tutto in una gamma cerca?
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: se A
viene creata la colonna NOT NULL
e -1
viene utilizzato un valore sentinella di invece il piano di esecuzione equivalente sembra sicuramente più semplice
Ma l'operatore di ricerca singola nel piano esegue ancora due ricerche invece di comprimerlo in un singolo intervallo contiguo e le letture logiche sono più o meno le stesse, quindi sospetto che forse sia abbastanza buono come sarà?
(NULL, 1000 )
@A
sia nullo o meno, sembra che non esegua una scansione. Ma non riesco a capire se i piani sono migliori della tua domanda. Fiddle-2
NULL
valori sono sempre i primi. (assunto il contrario). Condizione corretta a Fiddle