在赞恩对您的问题的评论中,他说:
...问题的一部分似乎是为了读取计划中的20K,您正在读取5000万行。
确实,这就是问题所在。没有索引可用于将部分或全部谓词下推到存储引擎。Microsoft在“文档”文章“时态表注意事项和限制 ”中为时态表推荐此基线索引策略:
最佳索引策略将包括当前表上的集群列存储索引和/或B树行存储索引,以及历史表上的集群列存储索引,以实现最佳的存储大小和性能。如果创建/使用自己的历史记录表,我们强烈建议您创建这种类型的索引,该索引由以期末列开头的期末列组成,以加快时间查询并加快数据一致性中的一部分查询校验。默认历史记录表具有基于期间列(结束,开始)为您创建的集群行存储索引。至少建议使用非集群行存储索引
措辞有点令人困惑(无论如何对我来说)。但要点是,您可以创建这些索引来提高性能,即使不是很多的话:
当前表的NC索引,以SysEndTime
:
CREATE NONCLUSTERED INDEX IX_SysEndTime_SysStartTime
ON dbo.Benefits (SysEndTime, SysStartTime)
/*INCLUDE (ideally, include your other important fields here)*/;
这样,您可以通过寻找适当的结束时间来避免读取当前表中的某些行。
历史记录表上的CCI
CREATE CLUSTERED COLUMNSTORE INDEX ix_BenefitsHistory
ON dbo.BenefitsHistory
WITH (DROP_EXISTING = ON);
这将使您在历史记录表上获得批处理模式,这将使扫描更快。
当前表的NC索引,以SysStartTime
:
有关为何难以为日期范围查询建立索引的更多详细信息,请参阅Paul对问题“ 最有效的日期范围检索方法”的回答。根据那里的逻辑,在当前表上添加另一个以SysStartTime开头的NC索引是有意义的,以便优化器可以根据统计信息和查询的特定参数选择使用哪个NC索引:
CREATE NONCLUSTERED INDEX IX_SysStartTime_SysEndTime
ON dbo.Benefits (SysStartTime, SysEndTime)
/*INCLUDE (ideally, include your other important fields here)*/;
在我的测试案例中,创建上面概述的3个索引在资源使用方面产生了显着差异。我设置了一个测试用例,它运行两个查询,返回总行数为150万。历史记录和当前表均具有5000万行)。
注意:为减少SSMS开销,我在启用“执行后丢弃结果”选项的情况下运行了测试。
执行计划-默认索引
逻辑读取:1,330,612
CPU时间:00:00:14.718
经过的时间:00:00:06.198
执行计划-上面描述了索引
逻辑读取:27,656(8,111行存储+ 19,545列存储)
CPU时间:00:00:01.828
经过的时间:00:00:01.150
如您所见,所有3个度量均显着下降-包括总耗时,从6秒降至1秒。
Docs文章提供的另一种选择是放弃当前表上的两个NC索引,转而使用聚集的列存储索引。在我的测试中,性能与上述索引解决方案非常相似。