执行计划的缓存和重新使用

更新日期: 2006 年 7 月 17 日

SQL Server 2005 有一个用于存储执行计划和数据缓冲区的内存池。池内分配给执行计划或数据缓冲区的百分比随系统状态动态波动。内存池中用于存储执行计划的部分称为过程缓存。

SQL Server 2005 执行计划包含下列主要组件:

  • 查询计划
    执行计划的主体是一个重入的只读数据结构,可由任意数量的用户使用。这称为查询计划。查询计划中不存储用户上下文。内存中永远不会有两个或多个查询计划副本:一个副本用于所有的串行执行,另一个用于所有的并行执行。并行副本覆盖所有的并行执行,与并行执行的并行度无关。
  • 执行上下文
    每个正在执行查询的用户都有一个包含其执行专用数据(如参数值)的数据结构。此数据结构称为执行上下文。执行上下文数据结构可以重新使用。如果用户执行查询而其中的一个结构未使用,将会用新用户的上下文重新初始化该结构。

执行上下文,同一查询,不同文字

在 SQL Server 2005 中执行任何 SQL 语句时,关系引擎将首先查看过程缓存中是否有用于同一 SQL 语句的现有执行计划。SQL Server 2005 将重新使用找到的任何现有计划,从而节省重新编译 SQL 语句的开销。如果没有现有执行计划,则 SQL Server 2005 将为查询生成新的执行计划。

SQL Server 2005 有一个高效的算法,可查找用于任何特定 SQL 语句的现有执行计划。在大多数系统中,这种扫描所使用的最小资源比通过重新使用现有计划而不是编译每个 SQL 语句所节省的资源要少。

该算法将新的 SQL 语句与缓存内现有的未用执行计划相匹配,并要求所有的对象引用完全合法。例如,在下列 SELECT 语句中,第一个语句与现有计划不匹配,而第二个语句匹配:

SELECT * FROM Contact

SELECT * FROM Person.Contact

在 SQL Server 2000 和 SQL Server 2005 的实例中重用单个执行计划的可能性要大于在 SQL Server 6.5 版和早期版本中重用的可能性。

执行计划的老化

生成执行计划后,它处于过程缓存中。只有需要空间时,SQL Server 2005 才使旧的未用计划从缓存老化掉。每个查询计划和执行环境都有相关的成本因子,可表明编译结构所需的费用。这些数据结构还有一个年龄字段。对象每由连接引用一次,其年龄字段便按编译成本因子递增。例如,如果查询计划的成本因子为 8 并且被引用了两次,则其年龄变为 16。惰性写入器进程定期扫描过程缓存中的对象列表。然后,惰性写入器减少每个对象的年龄字段,每扫描一次减少 1。在本例中,查询计划的年龄经过 16 次过程缓存扫描后减为 0,除非其他用户引用了该计划。如果满足下面三个条件,惰性写入器进程将释放对象:

  • 内存管理器需要内存而所有可用内存都正在使用。
  • 对象的年龄字段是 0。
  • 对象在当前没有被连接引用。

因为每次引用对象时其年龄字段都会增加,所以经常被引用的对象的年龄字段不会减为 0,也不会从缓存老化掉。不经常被引用的对象将很快满足释放条件,但是不会真被释放,除非其他对象有内存需求。

重新编译执行计划

根据数据库新状态的不同,数据库中的某些更改可能导致执行计划效率降低或无效。SQL Server 将检测到使执行计划无效的更改,并将计划标记为无效。此后,必须为执行查询的下一个连接重新编译新的计划。导致计划无效的情况包括:

  • 对查询所引用的表或视图进行更改(ALTER TABLE 和 ALTER VIEW)。
  • 对执行计划所使用的任何索引进行更改。
  • 对执行计划所使用的统计信息进行更新,该更新可能是从语句(如 UPDATE STATISTICS)中显示生成,也可能是自动生成的。
  • 删除执行计划所使用的索引。
  • 显式调用 sp_recompile
  • 对键的大量更改(其他用户对由查询引用的表使用 INSERT 或 DELETE 语句所产生的修改)。
  • 对于带触发器的表,插入的删除的表内的行数显著增长。
  • 使用 WITH RECOMPILE 选项执行存储过程。

为了使语句正确,或要获得可能更快的查询执行计划,大多数都需要进行重新编译。

在 SQL Server 2000 中,只要批处理中的语句导致重新编译,就会重新编译整个批处理,无论此批处理是通过存储过程、触发器、即席批查询,还是通过预定义的语句进行提交。在 SQL Server 2005 中,只有在批处理中导致重新编译的语句才会被重新编译。由于这种差异,SQL Server 2000 和 SQL Server 2005 中的重新编译计数不可比较。另外,由于 SQL Server 2005 扩展了功能集,因此,具有更多重新编译类型。

语句级重新编译有助于提高性能,因为在大多数情况下,只有少数语句导致了重新编译并造成相关损失(指 CPU 时间和锁)。因此,避免了批处理中其他不必重新编译的语句的这些损失。

SQL Server Profiler SP:Recompile 跟踪事件在 SQL Server 2005 中报告语句级重新编译。此跟踪事件在 SQL Server 2000 中仅报告批处理重新编译。此外,在 SQL Server 2005 中,将填充此事件的 TextData 列。因此,已不再需要 SQL Server 2000 中必须跟踪 SP:StmtStartingSP:StmtCompleted 以获取导致重新编译的 Transact-SQL 文本的做法。

SQL Server 2005 也添加了一个新跟踪事件,称为 SQL:StmtRecompile,它报告语句级重新编译。此跟踪事件可用于跟踪和调试重新编译。SP:Recompile 仅针对存储过程和触发器生成,而 SQL:StmtRecompile 则针对存储过程、触发器、即席批查询、使用 sp_executesql 执行的批处理、已准备的查询和动态 SQL 生成。

SP:RecompileSQL:StmtRecompileEventSubClass 列都包含一个整数代码,用以指明重新编译的原因。下表包含每个代码号的意思。

EventSubClass 值 说明

1

架构已更改。

2

统计信息已更改。

3

编译已延迟。

4

SET 选项已更改。

5

临时表已更改。

6

远程行集已更改。

7

FOR BROWSE 权限已更改。

8

查询通知环境已更改。

9

分区视图已更改。

10

游标选项已更改。

11

已请求 OPTION (RECOMPILE)。

ms181055.note(zh-cn,SQL.90).gif注意:
当 AUTO_UPDATE_STATISTICS 数据库选项被设置为 ON 时,如果查询以表或索引视图为目标,而表或索引视图的统计信息自上次执行后已更新或基数已发生很大变化,查询将被重新编译。此行为适用于标准用户定义表、临时表以及由 DML 触发器创建的 inserteddeleted 表。如果过多的重新编译影响到查询的性能,请考虑将此设置更改为 OFF。当 AUTO_UPDATE_STATISTICS 数据库选项设置为 OFF 时,不会因统计信息或基数的更改而发生任何重新编译,但是,由 DML INSTEAD OF 触发器创建的 inserteddeleted 表除外。因为这些表是在 tempdb 中创建的,因此,是否重新编译访问这些表的查询取决于 tempdb 中 AUTO_UPDATE_STATISTICS 的设置。请注意,在 SQL Server 2000 中,即使此设置为 OFF,查询仍然会基于 DML 触发器 inserteddeleted 表的基数变化进行重新编译。有关禁用 AUTO_UPDATE_STATISTICS 的详细信息,请参阅索引统计信息

请参阅

参考

SQL Server:SQL Statistics 对象

概念

缓冲区管理

其他资源

SQL Server 2005 中的批编译、重新编译和计划缓存问题

帮助和信息

获取 SQL Server 2005 帮助

更改历史记录

发布日期 历史记录

2006 年 7 月 17 日

新增内容:
  • 在使计划无效的情况列表中添加了使用 WITH RECOMPILE 选项执行存储过程。

2005 年 12 月 5 日

新增内容:
  • 阐明了当 AUTO_UPDATE_STATISTICS 数据库选项设置为 OFF 分别应用于由 DML INSTEAD OF 触发器创建的 inserted 表和 deleted 表时,重新编译查询的说明。