对简单查询生成执行计划(甚至是估计的执行计划)最多需要一分钟的时间是否正常?

J.D*_*.D. 1 sql-server execution-plan sql-server-2016

偶尔(但不常见)我的 SQL 服务器会花费看起来很奇怪的时间来生成执行计划。为以下相当简单的查询生成估计的执行计划只花了 37 秒:

SELECT *
FROM Table1
WHERE IndexedIntField1 = 12345
    AND NonIndexedVarcharField IN ('Value1', 'Value2', 'Value3')
Run Code Online (Sandbox Code Playgroud)

这个查询的结果数量大约为 500 行(来自一个包含大约 100 亿行的表),执行计划本质上是一个非聚集索引查找和键查找。

这是正常的吗?

编辑:

  • 表 1 是一个实际的物化常规基于磁盘的表(这里没有什么特别的)。
  • 它大约有 30 列宽。
  • 上面有 1 个聚集索引和 4 个非聚集索引。
  • 我的示例中的“IndexedIntField1”是 2 个非聚集索引中索引键的一部分,并且是第三个非聚集索引上的包含列。
  • “NonIndexedVarcharField”不是键,也不包含在任何索引中。
  • 我们每周至少更新一次表和索引的统计信息(有时一天一次或更多次)
  • 此表上没有花哨的计算列
  • 表上的索引非常简单,键列/包含列中只有几个字段,除了将“IndexedIntField1”作为键列的索引之一确实包含大约 15 列(因此它是一个相当大的索引) )。

Dav*_*oft 6

要处理这种形式的查询:

SELECT *
FROM Table1
WHERE IndexedIntField1 = 12345
    AND NonIndexedVarcharField IN ('Value1', 'Value2', 'Value3')
Run Code Online (Sandbox Code Playgroud)

基本的选择是扫描整个表或在IndexedIntField1上查找,然后对每一行执行查找以查看其他谓词是否获得。如果有很多行,IndexedIntField1 = 12345那么表扫描会便宜得多,如果行数很少,那么索引查找 + 书签查找会便宜得多。

如果决定使用哪个计划所需的统计信息不存在或已过期,则默认情况下,SQL Server 将在选择查询计划之前创建或更新统计信息。

当 AUTO_CREATE_STATISTICS 打开时,查询优化器为查询谓词中的单列创建统计信息。

https://docs.microsoft.com/en-us/sql/relational-databases/statistics/statistics?view=sql-server-ver15#CreateStatistics

AUTO_UPDATE_STATISTICS { ON | OFF } ON 指定查询优化器在查询使用统计信息以及它们可能已过期时更新统计信息。

https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-set-options?view=sql-server-ver15#auto_update_statistics

您可以像这样查看现有统计信息以及更新时间:

select *, stats_date(s.object_id, s.stats_id) stats_date
from sys.stats s
where object_id = object_id('sales.salesorderdetail')
Run Code Online (Sandbox Code Playgroud)