重新编译
我前面曾提到过,默认情况下存储过程会重用之前缓存的执行计划。但也有一些例外会导致重新编译。在SQL Server 2000中,重新编译发生在整个存储过程级别上,而在SQL Server 2005中,它可以发生于语句级别上。
与计划正确性(plan correctness)和计划最优性(plan optimality)相关的问题可能会导致这种情况。计划正确性问题包括基对象的架构更改(例如,添加/删除列、添加/删除索引等)或更改可以影响查询结果的SET选项(例如,ANSI_NULLS、CONCAT_NULL_ YIELDS_NULL等)。导致重新编译的计划最优性问题包括更改被引用对象的数据到一定程度,以致于使用新计划可能会更合适。例如,由于更新统计信息。
导致重新编译的两种原因有许多特例。在本节的最后,我将为你提供一个更为详细描述它们的资源。
当然,如果计划在一段时间内没有重用而被移出缓存,再次调用该存储过程时SQL Server将生成一个新的计划。
来看一个导致重新编译例子,运行下面的代码,它创建存储过程usp_CustCities。
|
该存储过程查询Customers表,并串联消费者三个物理位置:Country、Region和City。SET选项CONCAT_NULL_YIELDS_NULL默认为ON,表示当你用任意字符串和NULL串联时,得到的结果都为NULL。
第一次运行存储过程,你会得到表7-7所示的输出(被简化)。
|
CustomerID |
Country |
Region |
City |
CRC |
|
CACTU |
|
NULL |
|
NULL |
|
OCEAN |
|
NULL |
|
NULL |
|
RANCH |
|
NULL |
|
NULL |
|
ERNSH |
|
NULL |
|
NULL |
|
PICCO |
|
NULL |
|
NULL |
|
MAISD |
|
NULL |
Bruxelles |
NULL |
|
SUPRD |
|
NULL |
|
NULL |
|
QUEDE |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
RICAR |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
HANAR |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
GOURL |
|
SP |
|
Brazil.SP.Campinas |
|
WELLI |
|
SP |
Resende |
Brazil.SP.Resende |
|
TRADH |
|
SP |
|
Brazil.SP.Sao Paulo |
|
FAMIA |
|
SP |
|
Brazil.SP.Sao Paulo |
|
COMMI |
|
SP |
|
Brazil.SP.Sao Paulo |
|
… |
… |
… |
… |
… |
如你所见,只要Region为NULL,串联后的字符串则为NULL。SQL Server缓存了存储过程的执行计划以备日后重用。除了执行计划,SQL Server还会存储所有可以影响查询结果的SET选项。你可以在sys.syscacheobjects的setopts位图中观察到这一点。
设置CONCAT_NULL_YIELDS_NULL选项为OFF,通知SQL Server在串联时把NULL当作空字符串处理。
|
|
表7-8 CONCAT_NULL_YIELDS_NULL为OFF时usp_CustCities 的输出(被简化)
|
CustomerID |
Country |
Region |
City |
CRC |
|
CACTU |
|
NULL |
|
Argentina‥Buenos Aires |
|
OCEAN |
|
NULL |
|
Argentina‥Buenos Aires |
|
RANCH |
|
NULL |
|
Argentina‥Buenos Aires |
|
ERNSH |
|
NULL |
|
Austria‥Graz |
|
PICCO |
|
NULL |
|
Austria‥Salzburg |
|
MAISD |
|
NULL |
Bruxelles |
Belgium‥Bruxelles |
|
SUPRD |
|
NULL |
|
Belgium‥Charleroi |
|
QUEDE |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
RICAR |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
HANAR |
|
RJ |
|
Brazil.RJ.Rio de Janeiro |
|
GOURL |
|
SP |
|
Brazil.SP.Campinas |
|
WELLI |
|
SP |
Resende |
Brazil.SP.Resende |
|
TRADH |
|
SP |
|
Brazil.SP.Sao Paulo |
|
FAMIA |
|
SP |
|
Brazil.SP.Sao Paulo |
|
COMMI |
|
SP |
|
Brazil.SP.Sao Paulo |
|
… |
… |
… |
… |
… |
你可以看到,当Region为NULL,它被当作空字符串来处理,这样,CRC列就不会包含NULL了。在这个例子中,更改会话选项会改变查询的意义。运行这个存储过程时,SQL Server首先检查是否存在缓存的计划,且该计划所包含的状态与当前SET选项是否相同。SQL Server没发现这样的计划 ,所以它生成一个新的计划。注意,不论对SET选项的更改是否真的影响了查询的意义,SQL Server都会查询匹配的SET选项状态再重用计划。
查询sys.syscacheobjects,你会找到usp_CustCities的两个计划,并包含两个不同的setopts位图,如表7-9所示。
|
表7-9 sys.syscacheobjects 中usp_CustCities的执行计划
|
cacheobjtype |
objtype |
usecounts |
setopts |
sql |
|
Compiled Plan |
Proc |
1 |
4347 |
CREATE PROC dbo.usp_CustCities … |
|
Compiled Plan |
Proc |
1 |
4339 |
CREATE PROC dbo.usp_CustCities … |
当建立数据库连接时,客户端接口和工具通常会更改一些SET选项的状态。不同的客户端接口更改不同的SET选项,形成不同的执行环境。如果使用多个数据库接口和工具连接到数据库,而且它们拥有不同的执行环境,你将无法重用其他应用程序的计划。在应用程序连接到数据库时,通过运行一个跟踪,你可以很容易地识别出客户端工具更改的SET选项。如果发现执行环境有差异,你可以在所有的应用程序中显式地设置SET命令,并在建立连接时提交。通过这种方法,所有的应用程序都将拥有一致的执行环境并重用其他应用程序的计划。
实验完成后,把CONCAT_NULL_YIELDS_NULL选项改回ON:
|
| 回书目 上一节 下一节 |
|
· 第六章 你能帮我吗?.. · Linux笔试面试题选摘测.. · 08年5月软考网管上午真.. · 性能测试从零开始 目录 · 08年5月软考网工上午真.. · 上周拒绝服务攻击(DDo.. |
· 08年5月各大网上书店及.. · 2008年5月24日软考试题.. · 软件设计师专家临考模.. · 上周网络管理员专家自.. · 网络工程师自测获奖名.. · 08年4月各大网上书店及.. |