对于以下架构和示例数据
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
来代替相当于执行计划肯定看起来简单
但是,计划中的单个搜索运算符仍然执行两次搜索,而不是将其折叠到一个连续的范围内,并且逻辑读取值几乎相同,因此我怀疑这可能和它获得的效果一样好吗?
是的,我相信Oracle是与众不同的。
—
马丁·史密斯
@ypercube-不幸的是,SQL Server仅为该事件提供了有序扫描,因此重新读取了该应用程序已处理的所有行(逻辑读取为2015)。它没有
—
马丁史密斯
(NULL, 1000 )
在2种不同的条件下,无论是否
—
ypercubeᵀᴹ
@A
为null,似乎都不会进行扫描。但是我不明白这些计划是否比您的查询更好。小提琴2
NULL
价值观永远是第一位的。(假设相反)。在Fiddle中