我有一张这样的桌子:
CREATE TABLE Updates
(
UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
ObjectId INT NOT NULL
)
本质上跟踪ID不断增加的对象的更新。
该表的使用者将选择一个由100个不同的对象ID组成的块,这些ID UpdateId
由一个特定的并从其开始UpdateId
。从本质上讲,跟踪它停止的位置,然后查询任何更新。
我发现这是一个有趣的优化问题,因为我只能通过编写恰好由于索引而做我想要做的查询的查询来生成一个最大最优查询计划,但不能保证我想要的:
SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
@fromUpdateId
存储过程参数在哪里。
有以下计划:
SELECT <- TOP <- Hash match (flow distinct, 100 rows touched) <- Index seek
由于UpdateId
正在使用对索引的查找,因此结果已经不错,并且可以按照我想要的那样从最低更新ID到最高更新ID进行排序。这会生成一个流程明确的计划,这正是我想要的。但是排序显然不能保证行为,所以我不想使用它。
此技巧还导致了相同的查询计划(尽管具有冗余的TOP):
WITH ids AS
(
SELECT ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
ORDER BY UpdateId OFFSET 0 ROWS
)
SELECT DISTINCT TOP 100 ObjectId FROM ids
不过,我不确定(也不确定)这是否真的可以保证订购。
我希望SQL Server能够简化它的一个查询就是这样,但是最终生成了一个非常糟糕的查询计划:
SELECT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
GROUP BY ObjectId
ORDER BY MIN(UpdateId)
有以下计划:
SELECT <- Top N Sort <- Hash Match aggregate (50,000+ rows touched) <- Index Seek
我试图找到一种方法来生成具有索引查找功能的最佳计划,UpdateId
并以独特的流程删除重复的ObjectId
s。有任何想法吗?
如果需要,请提供样本数据。对象很少会有一个以上的更新,并且在一组100行中几乎不应该有一个以上的更新,这就是为什么我追求流程的不同,除非有我不知道的更好的东西?但是,不能保证单个ObjectId
表中的行数不会超过100。该表有超过1,000,000行,并且有望快速增长。
假设用户对此有另一种查找合适的next的方法@fromUpdateId
。无需在此查询中返回它。