对于以下架构和示例数据
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
应用程序正在以 1,000 行块的聚集索引顺序处理此表中的行。
从以下查询中检索前 1,000 行。
SELECT TOP 1000 *
FROM T
ORDER BY A, B
该组的最后一行如下
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
有没有办法编写一个查询,只寻找该复合索引键,然后跟随它来检索下一个 1000 行的块?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
到目前为止,我设法获得的最低读取次数是 1020,但查询似乎太复杂了。有没有更简单的相同或更高效率的方法?也许一个设法在一个范围内完成所有工作的人寻求?
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:如果创建列A
并NOT NULL
使用标记值-1
代替,等效的执行计划当然看起来更简单
但是计划中的单次搜索运算符仍然执行两次搜索,而不是将其折叠到一个连续的范围内,并且逻辑读取几乎相同,所以我怀疑这可能和它会得到的一样好?
我最喜欢的解决方案是使用
API
游标:总体策略是一次扫描,它会记住它在调用之间的位置。使用
API
游标意味着我们可以返回一组行,而不是像T-SQL
游标那样一次返回一个:STATISTICS IO
输出是: