Ebr*_*ani 10 performance sql-server temporal-tables
我在访问时态表中的历史记录时遇到了一个奇怪的问题。通过 AS OF 子句访问临时表中较旧条目的查询比对最近历史条目的查询花费的时间更长。
历史表是由 SQL Server 生成的(包括日期列上的聚集索引并使用页面压缩),我向历史表添加了 5000 万行,我的查询检索了大约 25,000 行。
我试图确定问题的根本原因,但无法确定。到目前为止,我已经测试过:
我想多看看这个,但我也想确保我没有吠错树。首先,是否有其他人在访问时态表中的旧历史数据时遇到过同样的行为(我们只注意到速度超过 1000 万行)?其次,我可以使用哪些策略来进一步隔离性能问题的根本原因(我刚刚开始研究执行计划,但对我来说仍然有点神秘)?
这些是简单的检索查询:第一个访问较旧的行,第二个访问较新的行。
较旧的行~1200 毫秒执行时间
最近行~350ms 执行时间
在赞恩对你的问题的评论中,他说:
...看起来您的问题的一部分是您正在读取 5000 万行以便在计划中返回 20K。
这确实是问题所在。没有索引可用于将部分或全部谓词推送到存储引擎。Microsoft 在 Docs 文章临时表注意事项和限制中为时态表推荐了这种基线索引策略:
最佳索引策略将包括当前表上的聚集列存储索引和/或 B 树行存储索引以及历史表上的聚集列存储索引,以实现最佳存储大小和性能。如果您创建/使用自己的历史表,我们强烈建议您创建这种类型的索引,该索引由周期列的结尾列开始,以加快时态查询以及作为数据一致性一部分的查询查看。默认历史记录表具有基于期间列(结束、开始)为您创建的聚集行存储索引。至少,建议使用非聚集行存储索引
措辞有点令人困惑(无论如何对我来说)。但要点是您可以创建这些索引来提高性能,如果不是很多的话:
SysEndTime
:CREATE NONCLUSTERED INDEX IX_SysEndTime_SysStartTime
ON dbo.Benefits (SysEndTime, SysStartTime)
/*INCLUDE (ideally, include your other important fields here)*/;
Run Code Online (Sandbox Code Playgroud)
这将允许您通过寻找适当的结束时间来避免读取当前表中的某些行。
CREATE CLUSTERED COLUMNSTORE INDEX ix_BenefitsHistory
ON dbo.BenefitsHistory
WITH (DROP_EXISTING = ON);
Run Code Online (Sandbox Code Playgroud)
这将使您在历史记录表上获得批处理模式,这将使扫描速度更快。
SysStartTime
:请参阅 Paul对“检索日期范围的最有效方法”问题的回答,了解有关日期范围查询的索引为何如此困难的更多详细信息。根据那里的逻辑,在以 SysStartTime 开头的当前表上添加另一个 NC 索引是有意义的,以便优化器可以根据统计信息和查询的特定参数选择使用哪个索引:
CREATE NONCLUSTERED INDEX IX_SysStartTime_SysEndTime
ON dbo.Benefits (SysStartTime, SysEndTime)
/*INCLUDE (ideally, include your other important fields here)*/;
Run Code Online (Sandbox Code Playgroud)
创建上面概述的 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 索引,转而使用聚集列存储索引。在我的测试中,性能与上述索引解决方案非常相似。
归档时间: |
|
查看次数: |
3877 次 |
最近记录: |