请解释sql server选择的查询计划

Posted

技术标签:

【中文标题】请解释sql server选择的查询计划【英文标题】:Please explain the query plan sql server chooses 【发布时间】:2009-03-12 14:41:04 【问题描述】:

在this blog post,我需要澄清一下为什么 SQL Server 会选择特定类型的扫描:

为了简单起见,我们假设 col1 是独一无二的,并且永远存在 值增加,col2 有 1000 不同的价值观,有 表中有 10,000,000 行,并且 聚集索引由 col1 组成, 并且非聚集索引存在于 col2.

想象一下查询执行计划 最初为以下创建 传递参数:@P1=1 @P2=99

这些值会导致 以下的最佳查询计划 使用替换的语句 参数:

Select * from t where col1 > 1 or col2

99 按 col1 排序;

现在,想象一下查询执行计划 如果初始参数值为: @P1 = 6,000,000 和 @P2 = 550。

和以前一样,最佳查询计划将 替换后创建 传递参数:

Select * from t where col1 > 6000000 或 col2 > 550 按 col1 排序;

这两个相同的参数化 SQL 语句可能会创建 和缓存非常不同的执行 由于计划的不同 最初传递的参数值。 但是,由于 SQL Server 只缓存 每个查询一个执行计划,机会 在第一种情况下非常高 查询执行计划将利用 聚集索引扫描,因为 ‘col1 > 1’ 参数替换。 而在第二种情况下,查询 使用索引查找的执行计划将 最有可能被创建。

来自:http://blogs.msdn.com/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx

为什么第一个查询使用聚集索引,而第二个查询使用索引查找?

【问题讨论】:

如果您从命令式更改标题,您可能会得到更多响应... 【参考方案1】:

假设列只包含正整数:

SQL Server 会查看表的统计信息,发现对于第一个查询,表中的所有行都满足 col1>1 的条件,因此它选择扫描聚集索引。

对于第二个查询,相对较小比例的行会满足 col1> 6000000 的条件,因此使用索引 seek 会提高性能。

【讨论】:

【参考方案2】:

请注意,在这两种情况下都将使用聚集索引。在第一个示例中,它是一个聚集索引 SCAN,而在第二个示例中,它将是一个聚集索引 SEEK,在大多数情况下,它会像博客作者所说的那样更快。

SQL Server 知道聚集索引正在增加。因此它会在第一种情况下进行聚集索引扫描。

【讨论】:

【参考方案3】:

如果优化器发现大部分表将在查询中返回,例如第一个查询,那么执行扫描比查找更有效。

如果只返回表的一小部分,例如在第二个查询中,则索引查找更有效。

scan 将触及表格中的每一行,无论它是否符合条件。成本与表中的总行数成正比。如果表很小或大多数行都符合谓词条件,则扫描是一种有效的策略。

seek 将触及符合条件的行和包含这些符合条件的行的页面,成本与符合条件的行和页面的数量成正比,而不是与表中的总行数成正比。

【讨论】:

以上是关于请解释sql server选择的查询计划的主要内容,如果未能解决你的问题,请参考以下文章

SQL -- SQL Server 查询优化器(Query Optimizers)

第十五周翻译-《Pro SQL Server Internals, 2nd edition》

提高sql server查询优化器结果的方法

sql server 统计信息

强制SQL Server执行计划使用并行提升在复杂查询语句下的性能

Sql Server 优化 SQL 查询:如何写出高性能SQL语句