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?
fonte
NULL
valores são sempre os primeiros. (assumiu o oposto.) Condição corrigida em Fiddle(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-2Respostas:
Uma das minhas soluções favoritas é usar um
API
cursor:A estratégia geral é uma única verificação que lembra sua posição entre as chamadas. Usar um
API
cursor significa que podemos retornar um bloco de linhas em vez de um de cada vez, como seria o caso de umT-SQL
cursor:A
STATISTICS IO
saída é:fonte