查询计划缓存及各种 SET 选项(与 showplan 相关及其他)
各种 SET 选项——多数与 showplan 相关——以多种复杂的方式影响着查询计划和执行上下文的编译、缓存和重用。下表汇总了相关的详细信息。
应按如下顺序阅读该表中的内容。批处理通过表中第一列所指定的特定模式提交给 SQL Server。已提交的批处理的计划缓存中可能存在、也可能不存在已缓存的查询计划。第 2 列和第 3 列描述了存在已缓存的查询计划时的情况;第 4 列和第 5 列说明了不存在已缓存的查询计划时的情况。在每个类别中,查询计划和执行上下文的各种情况都是独立的。表中说明了结构(查询计划或执行上下文)所发生的情况:是否被缓存、重用和使用。
模式名称 | 存在已缓存的查询计划时 | 存在已缓存的查询计划时 | 不存在已缓存的查询计划时 | 不存在已缓存的查询计划时 |
查询计划 | 执行上下文 | 查询计划 | 执行上下文 | |
showplan_text, showplan_all, showplan_xml | 被重用(无编译) | 被重用 | 被缓存(编译) | 生成一个执行上下文,对其进行缓存但不使用它 |
statistics profile, statistics xml, statistics io, statistics time | 被重用(无编译) | 不被重用生成并使用一个全新的执行上下文,但不对其进行缓存 | 被缓存(编译) | 生成并使用一个全新的执行上下文,但不对其进行缓存 |
noexec | 被重用(无编译) | 被重用 | 被缓存(编译) | 不生成执行上下文(由于“noexec”模式)。 |
parseonly(例如,在查询分析器或 Management Studio 中按“分析”按钮) | 无 | 无 | 无 | 无 |
对于每个查询计划和执行上下文,都会保留一个成本。该成本会在一定程度上控制计划或上下文在计划缓存中的存在时间。在 SQL Server 2000 和 SQL Server 2005 中,成本的计算和操作方式有所不同。详细情况如下。
SQL Server 2000:对于查询计划,成本用于度量查询优化器用于优化批处理的服务器资源(CPU 时间和 I/O)。对于特殊查询,其成本为零。对于执行上下文,成本用于度量用于初始化执行上下文以便各个语句做好执行准备的服务器资源(CPU 时间和 I/O)。请注意,执行上下文成本并不包含批处理执行期间所带来的成本(CPU 和 I/O)。通常,执行上下文成本低于查询计划成本。
以下说明了在 SQL Server 2000 中,批处理的查询计划如何带来成本开销。影响成本的因素有四个:生成计划所用的 CPU 时间 (cputime);从磁盘读取的页数 (ioread);写入磁盘的页数 (iowrite);以及批处理的查询计划所占的内存页数 (pagecount)。这样,查询计划成本可表示为(f 是一个数学函数):
Query plan cost c = f(cputime, ioread, iowrite) / pagecount
以下说明了在 SQL Server 2000 中,批处理的执行上下文如何带来成本开销。上方等式中单独的成本 c 将针对批处理中的每个语句进行计算,并加以累计。但是请注意,单独成本现在是语句初始化成本,而非语句编译或执行成本。
有时,惰性写入器进程会清除计划缓存并减少成本。将成本除于四,并根据需要四舍五入。(例如,25 --> 6 --> 1 --> 0。)当内存方面有压力时,成本为零的查询计划和执行上下文将从计划缓存中删除。重用查询计划或执行上下文时,其成本会被重置回编译(或执行上下文生成)成本。特殊查询的查询计划成本总是以 1 为单位逐渐递增。因此,频繁执行的批处理的查询计划在计划缓存中的存在时间要长于不频繁执行的批处理的计划。
SQL Server 2005:特殊查询的成本为零。另外,查询计划的成本用于度量生成其所需的资源量。尤其,该成本按“记号数”计算,最大值为 31,共由三部分组成:
成本 = I/O 成本 + 上下文开关成本(用于度量 CPU 成本) + 内存成本
该成本各部分的计算方法如下。
• | 两个 I/O 的成本为 1 个记号,最大成本为 19 个记号。 |
• | 另个上下文开关的成本为 1 个记号,最大成本为 8 个记号。 |
• | 十六个内存页 (128 KB) 的成本为 1 个记号,最大成本为 4 个记号。 |
在 SQL Server 2005 中,计划缓存不同于数据缓存。此外,还有一些特定于功能的缓存。在 SQL Server 2005 中,惰性写入器进程不会增加成本。相反,只要计划缓存的大小达到缓冲池大小的 50%,下一个计划缓存访问就会以 1 为单位减少所有计划的记号数。请注意,由于这种减少情况是随为查找计划而访问计划缓存的线程而产生的,因此可认为这一减少是以惰性方式进行的。在 SQL Server 2005 中,如果所有缓存大小的总和达到或超过了缓冲池大小的 75%,那么将激活一个专用的资源监视器线程,它将减少所有缓存中的所有对象的记号数。(所以该线程的行为方式与 SQL Server 2000 中的惰性写入器线程大致相同。)查询计划重用导致查询计划成本被重置为初识值。
五、文本其他部分的内容说明
到此,读者应该清楚:为了获得良好的 SQL Server 批处理执行性能,需要执行下列这两项操作:
• | 应尽可能重用查询计划。这可避免不必要的查询编译成本。计划重用还会带来更高的计划缓存使用率,而反过来又会实现更好的服务器性能。 |
• | 应避免可能造成查询编译次数增多的操作。减少重新编译次数可节省服务器资源(CPU 和内存),并增加批处理执行次数,同时达到预期性能。 |
下一节描述了有关查询计划重用的详细信息。同时,在适当位置给出了可实现更好的计划重用的最佳实务。再下一节中,我们介绍了可能导致重新编译次数增多的一些常见方案,并给出了避免发生这种情况的最佳实务。
六、查询计划重用计划缓存包含查询计划和执行上下文。概念上,查询计划同与之相关联的执行上下文相链接。批处理 S 的查询计划重用独立于 S 本身(比如:查询文本或存储过程名称)以及该批处理的一些外部因素(比如:生成 S 的用户名,生成 S 的 SET 选项,与 S 相关联的连接的 SET 选项等等)。有一些外部因素会影响计划重用:只要两个相同的查询在这些因素之一上有所不同,就将无法使用常见计划。而其他外部因素则不会影响计划重用。
大多数影响计划重用的因素都罗列在 sys.syscacheobjects 虚拟表中。下方列表描述了“典型用法”方案中的因素。在某些情况下,条目只会指出何时计划未被缓存(并因此永不被重用)。
通常,如果导致查询计划被缓存的连接的服务器、数据库和连接设置与当前连接的相应设置相同,就会重用查询计划。其次,批处理所引用的对象不要求名称解析。例如,Sales.SalesOrderDetail 不要求名称解析,而 SalesOrderDetail 则相反,因为名为 SalesOrderDetail 的表会存在于多个数据库中。大体上,完全合格的对象名称会为计划重用提供更多的机会。
影响计划重用的因素请注意,查询计划如果还未被缓存,就不能被重用。 所以,我们将仅明确指出无可缓存性,即表示无重用。
1. | 如果一个存储过程在数据库 D1 中执行,那么在不同的数据库 D2 中执行相同的存储过程时,就不会重用其查询计划。请注意,这一行为仅适用于存储过程,并不适用于特殊查询、预备的查询或动态 SQL。 | ||||||||||||||||||||||||||||||||||||
2. | 对于触发器执行,受执行影响的行数(1 比 n)——按被插入或被删除的表中的行数度量——是确定计划缓存命中的一个显著因素。请注意,该行为特别针对触发器,并不适用于存储过程。 在 SQL Server 2005 INSTEAD OF 触发器中,“1-plan”由影响 0 和 1 行的执行共享,而对于 non-INSTEAD OF ("after") 触发器,“1-plan”仅由影响 1 行的执行使用,同时“n-plan”由影响 0 和 n 行 (n > 1) 的执行使用。 | ||||||||||||||||||||||||||||||||||||
3. | 从不缓存大容量插入语句,但却缓存与大容量插入相关联的触发器。 | ||||||||||||||||||||||||||||||||||||
4. | 不缓存包含任何长于 8 KB 的文本的批处理。因此,无法缓存这种批处理的查询计划。(应用常量折叠之后,测量文本的长度。) | ||||||||||||||||||||||||||||||||||||
5. | 标有“复制标记”(与某位复制用户相关联)的批处理与没有该标记的批处理不相匹配。 | ||||||||||||||||||||||||||||||||||||
6. | 从 SQL Server 2005 的通用语言运行时 (CLR) 调用的批处理与从 CLR 外部提交的相同批处理不相匹配。然而,两个由 CLR 提交的批处理可重用相同的计划。相同的情况适用于:
| ||||||||||||||||||||||||||||||||||||
7. | 不缓存通过 sp_resyncquery 提交的查询的查询计划。所以,如果重新提交了(通过或不通过 sp_resyncquery 提交)该查询,就需要重新进行编译。 | ||||||||||||||||||||||||||||||||||||
8. | SQL Server 2005 允许在 T-SQL 批处理上定义游标。如果批处理被当作单独的语句提交,那么就不会对游标重用(部分)计划。 | ||||||||||||||||||||||||||||||||||||
9. | 下列 SET 选项会影响计划重用。
此外,ANSI_DEFAULTS 也会影响计划重用,因为其可用于同时更改下列 SET 选项(其中有一些会影响计划重用):ANSI_NULLS、ANSI_NULL_DFLT_ON、ANSI_PADDING、ANSI_WARNINGS、CURSOR_CLOSE_ON_COMMIT、IMPLICIT_TRANSACTIONS、QUOTED_IDENTIFIER. 上面这些 SET 选项会影响计划重用,因为 SQL Server 2000 和 SQL Server 2005 都能执行“常量折叠”(在编译时评估常量表达式以实现一些优化),而且这些选项的设置会影响这类表达式的结果。 部分上述 SET 选项的设置罗列在 sys.syscacheobjects 虚拟表中(比如:“langid”和“dateformat”。 请注意,可使用几种方法更改部分上述 SET 选项的值:
在 SET 选项存在冲突时,用户级和连接级 SET 选项值优先于数据库和服务器级 SET 选项值。另外,如果某个数据库级 SET 选项有效,那么对于引用多个数据库(可能拥有不同的 SET 选项值)的批处理,数据库(该批处理在其上下文中执行)的 SET 选项优先于其他数据库的 SET 选项。 最佳实务:为了避免与 SET 选项相关的重新编译,在连接时创建 SET 选项,并确保其在连接期间不会发生变化。 | ||||||||||||||||||||||||||||||||||||
10. | 带有不合格对象名的批处理不会重用查询计划。例如,在“SELECT * FROM MyTable”中,如果 Alice 发出了相应的查询并拥有带有相应名称的表,MyTable 可能会正常地解析到 Alice。同样,MyTable 可能解析到 Bob.MyTable。在这种情况下,SQL Server 不会重用查询计划。但是,如果 Alice 发出了“SELECT * FROM dbo.MyTable”,就不会存在不确定性,因为对象被唯一指定,并可重用查询计划。(请参见 sys.syscacheobjects 中的 uid 列。该列给出了生成计划的连接的用户 ID。只有带有相同用户 ID 的查询计划才可被重用。当 uid = -2 时,表示该查询不依赖于隐式名称解析,并可在不同的用户 ID 间共享。) | ||||||||||||||||||||||||||||||||||||
11. | 当通过“CREATE PROCEDURE ...WITH RECOMPILE”选项创建存储过程时,无论何时执行该存储过程,都不会缓存其查询计划。不存在计划重用的可能性:每次执行这种过程都会导致重新编译。 | ||||||||||||||||||||||||||||||||||||
12. | 最佳实务:“CREATE PROCEDURE ...WITH RECOMPILE”可用于标记通过各种参数调用的存储过程,而其最佳的查询计划高度依赖于在调用期间所提供的参数值。 | ||||||||||||||||||||||||||||||||||||
13. | 当使用“EXEC ...WITH RECOMPILE”执行存储过程 P 时,P 被重新编译。即使 P 的一个查询计划预先存在于计划缓存中并可被重用,也不会发生重用。不缓存为 P 全新编译的查询计划。 |
最佳实务:当通过非典型参数值执行存储过程时,“EXEC ...WITH RECOMPILE”可用于确保新的查询计划不会替代使用典型参数值编译的现有的已缓存计划。
“EXEC ...WITH RECOMPILE”还可与用户定义的函数一起使用,但只有在存在 EXEC 关键字时才可以。
1. | 为了避免通过不同的参数值执行的查询存在多个查询计划,应使用 sp_executesql 存储过程执行该查询。如果同一个查询计划有益于所有或大多数参数值,那么这种方法将很有用。 |
2. | 可缓存临时存储过程(针对会话范围及全局),因而可进行重用。 |
3. | 在 SQL Server 2005 中,不缓存创建或更新统计(手动或自动)的查询的计划。 |
回想一下,当 SQL Server 在批处理 B 中执行语句后,重新编译了某些(或所有)语句,这时 B 被重新编译。产生重新编译的原因可分为两大类:
• | 与正确性相关的原因。如果不进行重新编译会导致错误的结果或操作,那么就必须对批处理进行重新编译。与正确性相关的原因又可分为两类。
| ||||
• | 与计划最优性相关的原因。自 B 上次编译之后,B 所引用的表中的数据可能发生巨大的变化。在这种情况下,可能会对 B 进行重新编译,以便获得更快捷的查询执行计划。 |
下面两节将详细介绍这两个类别。
导致批处理重新编译的与正确性相关的原因后面列举了一些导致与正确性相关的重新编译的具体操作。因为必须进行这类重新编译,所以用户可以选择不进行这些操作,或者在 SQL Server 运行的非高峰期执行这些操作。
对象的架构1. | 无论批处理引用的任何对象在何时发生了架构更改,批处理都会被重新编译。“架构更改”的定义如下:
| ||||||||||||||
2. | 在存储过程或触发器上运行 sp_recompile 会导致它们在下一次执行时被重新编译。在表或视图上运行 sp_recompile 时,所有引用该表或视图的存储过程都将在下一次运行时被重新编译。sp_recompile 通过递增上述对象的磁盘上的架构版本来完成重新编译。 | ||||||||||||||
3. | 下列操作会刷新整个计划缓存,从而导致对之后所提交的批处理进行全新编译:
|
下列操作将刷新引用特定数据库的计划缓存条目,并随之导致全新编译。
• | DBCC FLUSHPROCINDB 命令 |
• | ALTER DATABASE ...MODIFY NAME = 命令 |
• | ALTER DATABASE ...SET ONLINE 命令 |
• | ALTER DATABASE ...SET OFFLINE 命令 |
• | ALTER DATABASE ...SET EMERGENCY 命令 |
• | DROP DATABASE 命令 |
• | 数据库自动关闭时 |
• | 当通过 CHECK OPTION 创建视图时,在其中创建该视图的数据库的计划缓存条目将被刷新。 |
• | 运行 DBCC CHECKDB 时,将创建指定数据库的一个副本。作为 DBCC CHECKDB 执行的一部分,将执行针对该副本的一些查询,并缓存其计划。在 DBCC CHECKDB 执行结束时,将删除该副本以及针对其的查询的查询计划。 “引用特定数据库的计划缓存条目”这一概念需要解释一下。数据库 ID 是计划缓存的键之一。假设执行了下列命令序列。 use master 假定在计划缓存中缓存了 Q。与 Q 的计划相关联的数据库 ID 将成为“master”而非“db1”的数据库 ID。 |
当 SQL Server 2005 的事务级快照隔离级别开启时,通常会发生计划重用。只要快照隔离级别下的批处理中的语句引用了一个对象(其架构自开启快照隔离模式后即被更改),同时缓存并重用了该语句的查询计划,就会发生语句级重新编译。全新编译的查询计划将被缓存,而该语句本身则会失败(根据相应隔离级别的语义)。如果未缓存查询计划,就会发生编译,随后被编译的查询计划会被缓存,而语句本身则会失败。
SET 选项正如第 6 节已经提到的,在批处理开始执行后更改下列 SET 选项中的一项或多项,将导致重新编译:ANSI_NULL_DFLT_OFF、ANSI_NULL_DFLT_ON、ANSI_NULLS、ANSI_PADDING、ANSI_WARNINGS、ARITHABORT、CONCAT_NULL_YIELDS_NULL、DATEFIRST、DATEFORMAT、FORCEPLAN、LANGUAGE、NO_BROWSETABLE、NUMERIC_ROUNDABORT、QUOTED_IDENTIFIER。
导致批处理重新编译的与计划最优性相关的原因SQL Server 设计用于当数据库中的数据更改时,生成最佳的查询执行计划。使用 SQL Server 的查询处理器中的统计(直方图)来跟踪数据更改。所以,与计划最优性相关的原因同统计密切相关。
开始详细介绍与计划最优性相关的原因之前,让我们列出不会发生与计划最优性相关的重新编译的情况。
• | 当计划属于“常用计划”时。当查询优化器决定查询所引用的给定表及其上的索引时,将产生常用计划,只能有一个计划。显而易见,在这种情况下进行重新编译并没有什么用。当然,生成过常用计划的查询不一定总是生成这类计划。例如,可能在基础表上创建新的索引,从而就有多个访问路径供查询优化器使用。如第 7.1 节所提到的,所添加的这类索引将被删除,而与正确性相关的重新编译可能将常用计划替换为非常用计划。 |
• | 当查询包含“KEEPFIXED PLAN”提示时,不会出于与计划最优性相关的原因重新编译该查询的计划。 |
• | 当查询计划引用的所有表都为只读时,该计划将被重新编译。 |
• | 这一点只适用于 SQL Server 2000。假定某个查询计划被编译(不是重新编译),而作为编译的一部分,查询处理器将决定更新表 T 上的统计 S。查询处理器试图在 T 上获取一个特殊的“统计锁”。如果其他进程正在更新 T 上的某个统计(不一定是 S!),查询处理器就无法在 T 上获得统计锁。在这种情况下,查询处理器不会更新 S。另外,上述查询计划不会再因为与计划最优性相关的原因而被重新编译。这就像通过“KEEPFIXED PLAN”提示提交查询一样。 |
• | 这种情况与上面着重提到的一个情况相同,只是此处的查询计划被缓存了。换句话说,这种情况涉及重新编译,而前面的那个情况与之相反,仅涉及编译。对于这种重新编译情形,假设查询处理器试图在 T 上获得一个“统计锁”,但失败了。在这种情况下,查询处理器会跳过对统计 S 的更新;使用过时的统计 S;并同平常一样,通过其他重新编译步骤/检查继续进行操作。因而,借助可能较慢的查询执行计划可避免重新编译。 |
下方流程图简单明了地描述了 SQL Server 中的批处理编译和重新编译过程。主要的处理步骤如下所示(本文档后面将对各个步骤进行详细介绍):
1. | SQL Server 开始编译一个查询。(正如前面提到的,批处理是一个编译和缓存单位,而批处理中的各个语句则是逐一进行编译。) |
2. | 可能有助于生成最佳查询计划的所有“引起关注的”统计都将从磁盘载入内存。 |
3. | 如果任何统计过时了,那么将逐一对其进行更新。查询编译将等待更新的结束。对于这一步骤,SQL Server 2000 和 SQL Server 2005 间的一个重要不同之处在于:在 SQL Server 2005 中,可能会有选择地对统计进行异步更新。也就是说,统计更新线程不阻止查询编译线程。编译线程将用状态统计继续操作。 |
4. | 生成查询计划。查询中所引用的所有表的重新编译阈值随查询计划一起被保存。 |
5. | 这时,查询执行在理论上已经开始。现在测试查询计划以查找与正确性相关的原因。相关原因在第 7.1 中有所描述。 |
6. | 如果就任何与正确性相关的原因而言,计划不正确,那么将开始进行重新编译。请注意,由于查询执行在理论上已经开始了,因此刚刚开始的编译即为重新编译。 |
7. | 如果计划“正确”,那么各种重新编译阈值将与表基数或各种表修改计数器(SQL Server 2000 中的 rowmodctr 或 SQL Server 2005 中的 colmodctr)相比较。 |
8. | 如果根据步骤 7 中进行的比较认定有任何统计过时了,那么将进行重新编译。 |
9. | 如果步骤 7 中的所有比较都成功完成,那么将开始实际的查询执行。 |
每个 SELECT、INSERT、UPDATE 和 DETELE 语句都访问一个或多个表。表内容因 INSERT、UPDATE 和 DELETE 等操作而发生变化。SQL Server 的查询处理器设计用于通过潜在地生成不同的查询计划(每个查询计划在生成时都是最佳的),来适应这种变化。使用表基数直接跟踪表内容,并使用表列上的统计(直方图)进行间接跟踪。
每个表都有一个与之相关联的重新编译阈值 (RT)。RT 是表中列数的一个函数。在查询编译期间,查询处理器将不载入或载入若干个在查询中引用的表上的统计。这些统计被称为引人关注的统计。对于查询中引用的每个表,已编译的查询计划包含:
• | 重新编译阈值 |
• | 列出查询编译期间载入的所有统计的列表对于每个统计,将保存计算表修改次数的计数器的快照值。在 SQL Server 2000 中,该计数器被称为 rowmodctr,而在 SQL Server 2005 中则称为 colmodctr。每个表列中都存在一个单独的 colmodctr(非永久性计算列除外)。 |
| modctr(snapshot) – modctr(current) | >= RT
modctr(current) 表示修改计数器的当前值,而 modctr(snapshot) 表示查询计划上次编译时修改计数器的值。如果阈值交叉在任何令人关注的统计上取得了成功,那么将重新编译查询计划。在 SQL Server 2000 中,包含该查询的整个批处理都被重新编译;而在 SQL Server 2005 中,仅重新编译上述查询。
如果表或索引视图 T 上没有统计,或者在查询编译期间 T 上现有的统计都不被认为是“令人关注的”,那么仍会仅根据 T 的基数,执行下列阈值交叉测试。
| card(snapshot) – card(current) | >= RT
card(current) 表示当前 T 中的行数,而 card(snapshot) 表示查询计划上次编译时的行数。
下面几节将介绍“整体情况”中引入的几个重要概念。
“令人关注”的统计的概念对于每个查询计划 P,优化器保存被载入以生成 P 的统计的 ID。请注意,“载入的”集同时包含:
• | 用作操作符(显示在 P 中的)的基数评估器的统计 |
• | 用作查询计划(在查询优化期间加以考虑但为了支持 P 而被抛弃)中的基数评估器的统计 |
换而言之,查询优化器出于某个原因或其他原因,将载入的统计认作是“令人关注的”。
回想一下,统计可以手动或自动创建或更新。还会因执行下列命令而导致统计更新:
• | CREATE INDEX ...WITH DROP EXISTING |
• | sp_createstats 存储过程 |
• | sp_updatestats 存储过程 |
• | DBCC DBREINDEX(但不是 DBCC INDEXDEFRAG!) |
表的重新编译阈值可部分决定引用该表的查询的重新编译频率。RT 取决于表类型(永久或临时)以及编译查询计划时表中的行数(基数)。在批处理中引用的所有表的重新编译阈值都将随该批处理的查询计划一起保存。
RT 的计算方法如下所示。(n 表示编译查询计划时表的基数。)
• | 永久表
| ||||||
• | 临时表
| ||||||
• | 表变量
|
表修改计数器(rowmodctr 和 colmodctr)
如上所述,RT 与表所执行的修改次数进行了对比。使用称为 rowmodctr(在 SQL Server 2000 中)和 colmodctr(在 SQL Server 2005 中)的计数器跟踪表所进行的修改次数。 这两种计数器都不是针对具体事务的。例如,如果启动了某个事务,并在表中插入了 100 行,然后再回滚操作,那么对修改计数器所作的更改将不会被回滚。
Rowmodctr (SQL Server 2000)每个表都有一个 rowmodctr 与之相关联。其值可从 sysindexes 系统表获得。在表或索引视图 T 的一个或多个列上创建的每个统计都有一个 rowmodctr 的快照值与之相关联。无论该统计何时被更新——手动或自动(通过 SQL Server 的自动统计功能),rowmodctr 的快照值也会被刷新。有关 rowmodctr 的详细信息在下方白皮书中有所描述:http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28000409
“阈值交叉”测试中所提到的 Rowmodctr(current) 是 sysindexes 系统表(针对堆栈或聚集索引)在查询编译期间进行测试时所保留的值。
rowmodctr 可在 SQL Server 2005 服务器上使用,但其值总为 0。
补充说明一下,在 SQL Server 2000 中,当 rowmodctr 为 0 时,将无法导致重新编译。
Colmodctr (SQL Server 2005)与 rowmodctr 不同,每个表列都会保存一个 colmodctr 值(非永久性计算列除外)。同普通列一样,永久性计算列拥有 colmodctr。使用 colmodctr 值,可以更细化地跟踪表的更改。Colmodctr 值对用户不可用;仅供查询处理器使用。
当在表或索引视图 T 的一个或多个列上(通过自动统计功能手动或自动)创建或更新统计时,最左边一列的 colmodctr 的快照值将保存在统计二进制大对象 (stats-blob) 中。
“阈值交叉”测试中所提到的 Colmodctr(current) 在查询编译期间进行测试时保留在 SQL Server 2005 的元数据中的值。
与 rowmodctr 不同,colmodctr 的值是一个不断递增的序列:colmodctr 值从不被重置为 0。
不存在非永久性计算列的 Colmodctr 值。其派生自参与计算的列。
使用 rowmodctr 和 colmodctr 跟踪表和索引视图的更改由于 rowmodctr 和 colmodctr 值用于做出重新编译决定,因此它们的值被当作表更改来进行修改。在下列描述中,我们仅提到了表。但是,相同的情况也适用于索引视图。可通过下列语句更改表:INSERT、DELETE、UPDATE、大容量插入和表截断。下列表定义了修改 rowmodctr 和 colmodctr 值的方式。
语句 | SQL Server 2000 | SQL Server 2005 |
INSERT | rowmodctr += 1 | 所有 colmodctr += 1 |
DELETE | rowmodctr += 1 | 所有 colmodctr += 1 |
UPDATE | rowmodctr += 2 或 3。“2”的说明:1 表示删除 + 1 表示插入。 | 如果更新针对非键列:colmodctr += 1 针对所有已更新的列。 如果更新针对键列:colmodctr += 2 针对所有列。 |
大容量插入 | 不更改。 | 与 n INSERT 相同。所有 colmodctr += n。(n 是大容量插入的行数。) |
表截断 | 不更改。 | 与 n DELETE 相同。所有 colmodctr += n。(n 是表的基数。) |