Para o seguinte esquema e dados de exemplo
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
Um aplicativo está processando as linhas desta tabela em ordem de índice clusterizado em 1.000 pedaços de linha.
As primeiras 1.000 linhas são recuperadas da consulta a seguir.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
A linha final desse conjunto está abaixo
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
Existe alguma maneira de escrever uma consulta que apenas busque nessa chave de índice composta e a siga para recuperar o próximo pedaço de 1000 linhas?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
O menor número de leituras que consegui chegar até agora é 1020, mas a consulta parece complicada demais. Existe uma maneira mais simples de igual ou melhor eficiência? Talvez alguém que consiga fazer tudo de uma só vez procure?
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 coluna A
for criada NOT NULL
e um valor sentinela -1
for usado, o plano de execução equivalente certamente parecerá mais simples
Mas o operador de busca única no plano ainda realiza duas buscas vez de reduzi-las em um único intervalo contíguo e as leituras lógicas são as mesmas, então eu suspeito que talvez isso seja tão bom quanto possível?
(NULL, 1000 )
@A
é nulo ou não, parece que não faz uma varredura. Mas não consigo entender se os planos são melhores que a sua consulta. Fiddle-2
NULL
valores são sempre os primeiros. (assumiu o oposto.) Condição corrigida em Fiddle