las*_*exi 2 performance sql-server execution-plan query-performance
附带的计划运行时间不应超过一分钟,但有时需要数小时。两个外部聚集索引上的 I/O 扫描气球失控,查询爬行。有人可以向我解释为什么会发生这种情况以及如何解决吗?
让我们从右到左跟踪查询计划。SQL Server 估计从t1派生表中只会返回一行。对于返回的每一行,它将对VoterTelephones节点 ID 为 20 和 26中的表进行聚集索引扫描。这意味着如果t1派生表的基数估计是错误的,那么 SQL Server 最终可能会执行比预期更多的聚集索引扫描花费这个计划。例如,如果从t1派生表返回一千行,则 SQL Server 可能会对该VoterTelephones表执行 2000 次聚集索引扫描。如果 SQL Server 有更准确的基数估计,那么它可能会选择不同的查询计划。
还有另一种技术性较低的方法可以得出类似的结论。这次我们从查询计划的左边开始。SQL Server 认为只有一行会被插入到#tmpKeep1表中。真的吗?如果您认为它不是真的,那么查询计划的估计成本可能非常不准确。该计划的估计成本为 50 个魔法优化器单元,但查询有时需要数小时才能完成。这是认为成本与执行查询时实际发生的情况相比不准确的另一个原因。如果 SQL Server 对您的数据做出了错误的假设或估计,那么它可能选择了一个次优查询计划来返回您的数据。
为了提高查询性能,我首先尝试纠正从 t1 派生表返回的基数估计:
--get dupe cell phones
select TelAreaCode, TelNumber
from VoterTelephones
where TelCellFlag = 1 group by TelAreaCode, TelNumber having count(*) > 1
Run Code Online (Sandbox Code Playgroud)
最直接的方法是将该查询的结果放入临时表中。SQL Server 将收集临时表上的统计信息,因此您将获得更准确的基数估计,这可能会更改查询计划。
根据您的 SQL Server 版本,您可以通过在VoterTelephones表上创建多列统计对象,甚至仅通过使用 FULLSCAN 更新统计信息来改进估计。包含where TelCellFlag = 1谓词的过滤统计信息也可能有所帮助。这里的想法是,如果您向 SQL Server 提供有关您的数据的更多信息,那么它可能能够为您提供该派生表的更好基数估计。
从查询的那部分修复基数估计太困难了,这可能是真的。在这种情况下,您可以尝试在VoterTelephones表上创建索引,从而无需 SQL Server 对外部表中的每一行进行聚集索引扫描。如果在表上创建覆盖索引,则 SQL Server 将对外部结果集中的每行进行索引查找,而不是每行进行聚集索引扫描。那应该效率更高。
对于在vtTelCellFlag 列上过滤时别名的表的连接,在TelAreaCode和TelNumber列上连接,并且查询的其他部分也需要LALVoterID和TelMatchScore列。您可以通过仔细解析查询文本或查看节点 ID 为 7 的嵌套循环连接运算符和节点 ID 为 20 的聚集索引扫描来获取该信息。例如,这里是扫描的谓词:
[S_MS].[dbo].[VoterTelephones].[TelCellFlag] as [vt].[TelCellFlag]=(1)
Run Code Online (Sandbox Code Playgroud)
这是嵌套循环运算符的连接谓词:
[S_MS].[dbo].[VoterTelephones].[TelAreaCode] as [vt].[TelAreaCode]
=[S_MS].[dbo].[VoterTelephones].[TelAreaCode]
AND [S_MS].[dbo].[VoterTelephones].[TelNumber] as [vt].[TelNumber]
=[S_MS].[dbo].[VoterTelephones].[TelNumber]
Run Code Online (Sandbox Code Playgroud)
这是聚集索引扫描的输出列列表:
[S_MS].[dbo].[VoterTelephones].LALVoterID,
[S_MS].[dbo].[VoterTelephones].TelNumber,
[S_MS].[dbo].[VoterTelephones].TelMatchScore,
[S_MS].[dbo].[VoterTelephones].TelAreaCode
Run Code Online (Sandbox Code Playgroud)
您可以组合这些数据来确定您对索引的需求。您希望谓词和连接列位于索引列中,而其他必要的列要包含在列中。这样的事情可以工作:
CREATE INDEX NAME_YOUR_INDEX ON VoterTelephones (TelCellFlag, TelAreaCode, TelNumber)
INCLUDE (LALVoterID, TelMatchScore);
Run Code Online (Sandbox Code Playgroud)
您可以对计划中的其他索引扫描(节点 ID 26)执行类似的分析。
根据您的应用程序,您也可能会遇到临时表的计划缓存或统计缓存问题。我认为这不太可能是原因,但我将其包括在内,以防其他想法不起作用。您可以通过RECOMPILE在查询中包含提示来对此进行测试。根据此查询运行的频率,这可能不是一个好的选择。
| 归档时间: |
|
| 查看次数: |
569 次 |
| 最近记录: |