线轴
在SQL Server中,有几种类型的线轴。我感兴趣的两个是Table Spool和Index spool,它们在修改查询之外。
只读查询(尤其是在嵌套循环联接的内侧)可以使用表或索引假脱机来潜在地减少I / O并提高查询性能。这些线轴可以是Eager或Lazy。就像你我一样。
我的问题是:
- 哪些因素影响表与索引假脱机的选择
- 哪些因素构成了热切线轴和惰性线轴之间的选择
在SQL Server中,有几种类型的线轴。我感兴趣的两个是Table Spool和Index spool,它们在修改查询之外。
只读查询(尤其是在嵌套循环联接的内侧)可以使用表或索引假脱机来潜在地减少I / O并提高查询性能。这些线轴可以是Eager或Lazy。就像你我一样。
我的问题是:
Answers:
这有点宽泛,但是我认为我理解“真正的问题”,并将对此做出相应的回答。只是要谈论表vs索引假脱机。我认为在表和索引假脱机之间进行选择是不正确的。如您所知,有可能在单个子树中获取索引后台处理程序,表后台处理程序,或者同时获取索引后台处理程序和表后台处理程序。我认为在以下情况下获得索引假脱机通常是正确的:
您可以通过简单的演示看到其中的大多数。首先创建一对堆:
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
对于第一个查询,没有什么可以寻找的:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);
因此,优化器没有理由将联接转换为应用。由于成本原因,您最终得到了一个表假脱机。因此,此查询无法通过第一个测试。
对于下一个查询,可以合理地期望优化器有理由考虑应用:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
但这并不意味着:
此查询第二次测试失败。完整的解释在这里。引用最相关的部分:
优化器不会考虑动态建立索引以启用应用;相反,事件的顺序通常是相反的:因为存在良好的索引,所以可以应用变换。
我可以重写查询,以鼓励优化器考虑应用:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);
但是仍然没有索引假脱机:
该查询在第三次测试中失败。在SQL Server 2014中,索引键的长度限制为900字节。这在SQL Server 2016中得到了扩展,但仅适用于非聚集索引。线轴的索引是聚集索引,因此限制保持在900字节。在任何情况下,都不能应用索引假脱机规则,因为它可能导致查询执行期间出错。
将数据类型长度减少到800最终提供了一个带有索引假脱机的计划:
毫无疑问,索引假脱机计划的成本比没有假脱机的计划便宜得多:89.7603个单元对598.832个单元。您可以通过未记录的QUERYRULEOFF BuildSpool
查询提示看到区别:
这不是一个完整的答案,但希望它是您想要的一些东西。