Para el siguiente esquema y datos de ejemplo
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
Una aplicación está procesando las filas de esta tabla en orden de índice agrupado en 1,000 fragmentos de fila.
Las primeras 1000 filas se recuperan de la siguiente consulta.
SELECT TOP 1000 *
FROM T
ORDER BY A, B
La fila final de ese conjunto está debajo
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
¿Hay alguna forma de escribir una consulta que solo busque en esa clave de índice compuesta y luego la siga para recuperar el siguiente fragmento de 1000 filas?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
El número más bajo de lecturas que he logrado hasta ahora es 1020, pero la consulta parece demasiado complicada. ¿Existe una forma más simple de igual o mejor eficiencia? Tal vez uno que logra hacer todo en un rango de búsqueda?
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: Si la columna A
está hecha NOT NULL
y un valor centinela de -1
su lugar se usa el plan de ejecución equivalente sin duda parece más sencillo
Pero el operador de búsqueda única en el plan todavía realiza dos búsquedas en lugar de colapsarlo en un solo rango contiguo y las lecturas lógicas son muy similares, así que sospecho que tal vez esto sea tan bueno como sea posible.
(NULL, 1000 )
@A
es nulo o no, parece que no hace un escaneo. Pero no puedo entender si los planes son mejores que su consulta. Fiddle-2
NULL
valores son siempre los primeros. (asumió lo contrario.) Condición corregida en Fiddle