背景
我注意到在尝试运行总查询时,有时估计的计划只显示“获取查询”
并且实际计划显示从聚集索引扫描中重复获取
在其他情况下(例如TOP
,在查询中添加 a 时),估计的计划显示填充工作表的“Population Query”阶段
实际计划显示聚集索引扫描以填充工作表,然后重复查找该工作表。
问题
- SQL Server 在选择一种方法而不是另一种方法时使用什么标准?
- 我认为第一种方法(没有额外的工作表填充步骤)更有效吗?
(额外的问题:如果有人能解释为什么第一个查询中的每次扫描都算作 2 次逻辑读取,这可能也很有启发性)
附加信息
我在这里找到了这篇文章,它解释了FAST_FORWARD
游标可以使用动态计划或静态计划。在这种情况下,第一个查询似乎使用动态计划,第二个查询似乎使用静态计划。
我还发现,如果我尝试
SET @C2 = CURSOR DYNAMIC TYPE_WARNING FOR SELECT TOP ...
游标被隐式转换为keyset
游标,因此很明显TOP
动态游标不支持该构造,这可能是鲁本回答中的原因 - 仍在寻找对此的明确解释。
然而,我也读到动态游标往往比它们的静态游标(源 1,源 2 )慢,这让我感到惊讶,因为静态类型必须读取源数据,复制它,然后读取副本而不仅仅是读取源数据。我之前引用的文章提到动态游标使用. 谁能解释这些是什么?它只是一个 RID 或 CI 密钥,还是不同的东西?markers
脚本
SET STATISTICS IO OFF
CREATE TABLE #T ( ord INT IDENTITY PRIMARY KEY, total INT, Filler char(8000))
INSERT INTO #T (total) VALUES (37),(80),(55),(31),(53)
DECLARE @running_total INT,
@ord INT,
@total INT
SET @running_total = 0
SET STATISTICS IO ON
DECLARE @C1 AS CURSOR;
SET @C1 = CURSOR FAST_FORWARD FOR SELECT ord, total FROM #T ORDER BY ord;
OPEN @C1;
PRINT 'Initial FETCH C1'
FETCH NEXT FROM @C1 INTO @ord, @total ;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @running_total = @running_total + @total
PRINT 'FETCH C1'
FETCH NEXT FROM @C1 INTO @ord, @total ;
END
SET @running_total = 0
SET STATISTICS IO ON
DECLARE @C2 AS CURSOR;
SET @C2 = CURSOR FAST_FORWARD FOR SELECT TOP 5 ord, total FROM #T ORDER BY ord;
OPEN @C2;
PRINT 'Initial FETCH C2'
FETCH NEXT FROM @C2 INTO @ord, @total ;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @running_total = @running_total + @total
PRINT 'FETCH C2'
FETCH NEXT FROM @C2 INTO @ord, @total ;
END
PRINT 'End C2'
DROP TABLE #T