我们的数据库有许多表格,这些表格遵循"仅插入"架构。行添加到最后,"当前"然后,可以通过查找每个逻辑密钥的最近插入行来找到该值。
以下是一个例子:
CREATE TABLE [dbo].[SPOTQUOTE](
[ID] [numeric](19, 0) NOT NULL,
[QUOTETYPE] [varchar](255) NOT NULL,
[QUOTED_UTC_TS] [datetime] NOT NULL,
[QUOTED_UTC_MILLIS] [smallint] NOT NULL,
[RECEIVED_UTC_TS] [datetime] NOT NULL,
[RECEIVED_UTC_MILLIS] [smallint] NOT NULL,
[VALUE_ASK] [float] NULL,
[VALUE_BID] [float] NULL,
[FEEDITEM_ID] [numeric](19, 0) NOT NULL,
[SAMPLING] [int] NOT NULL,
CONSTRAINT [SPOTQUOTE_pk1] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
此表的逻辑键是" feeditem_id"。但是,我们可以执行历史查询,而是只使用" ID"作为实际的物理钥匙。
因此,我们知道每个不同的feeditem_id的max(id)将在表的末尾找到,而不是在开头。
查询表格时,我们希望找到最新的"更新每个" feeditem_id",这是"逻辑键"对于这张桌子。
以下是我们想要的查询:
select feeditem_id, max(id)
from spotquote
group by feeditem_id
having feeditem_id in (827, 815, 806)
这样我们就可以获得每个feeditem_id的最新ID。
不幸的是,SQL Server 2008为此查询生成了一个次优查询计划。
根据我对SQL的理解,这是为最大id选择的事实,这是主要的群集密钥,这意味着最佳查询计划是:
我希望这会非常快。
第一个问题:我是否可以通过某种方式明确告诉SQL服务器执行上述查询计划?
我试过了:
SELECT feeditem_id, max(ID) as latest from SPOTQUOTE with (index(SPOTQUOTE_pk1)) group by feeditem_id
having FEEDITEM_ID in (827, 815, 806)
但是,在实践中,它似乎执行得更慢。
我想知道"聚集索引扫描"正在向前走,而不是倒退...有没有办法可以确认这是不是正在发生的事情?
如何确认此聚簇索引扫描是否从表的后面开始工作,以及如何说服SQL服务器向后搜索聚簇索引?
更新
问题确实是当我执行分组时,聚集索引扫描不会向后搜索。
相反,以下SQL查询基本上生成了正确的查询计划:
select
FEEDITEM_ID, MAX(id) from
(select top 100 * from
SPOTQUOTE
where FEEDITEM_ID in (827,815,806)
order by ID desc) s
group by feeditem_id
我可以在管理工作室看到" Ordered = True"和"扫描方向=后退":
它执行速度非常快 - 2毫秒 - 而且几乎可以肯定"的工作原理。
我只是想要"停止"一旦找到每个Feed id的条目而不是前100个条目。
令人沮丧的是,似乎没有办法告诉SQL服务器执行这个明显更高效的查询。
如果我通过"做一个正常的"组。使用feeditem_id和id上的适当索引,速度更快 - 大约300毫秒 - 但仍然比向后聚集索引扫描慢100倍。
答案 0 :(得分:1)
SQL Server无法生成截至2012年的此类查询计划。重写查询:
SELECT ids.feeditem_id, MaxID
FROM (VALUES (827), (815), (806)) ids(feeditem_id)
CROSS APPLY (
select TOP 1 ID AS MaxID
from spotquote sq
where sq.feeditem_id = ids.feeditem_id
ORDER BY ID DESC
) x
这会产生一个计划,可以根据您指定的ID查找spotquote
表。这是我们能做的最好的事情。只要您感兴趣的所有组至少有一个值,SQL Server就无法中止聚合。