《Microsoft Sql server 2008 Internal》读书笔记--第九章Plan Caching and Recompilation(2)

 

《Microsoft Sql server 2008 Internals》读书笔记订阅地址:

http://www.cnblogs.com/downmoon/category/230397.html/rss

《Microsoft Sql server 2008 Internals》索引目录:

《Microsoft Sql server 2008 Internal》读书笔记--目录索引

 

在这一节,我们将继续关注Adhoc和参数化

Adhoc混合负载的优化

如果你的查询大多数是临时(adhoc)的,从来不会被重用,似乎浪费内存去缓存这些计划了。SQL Server 2008增加了一个配置选项在这种情况下也能满足你的需求。一旦选项启用,仅仅在第一次任何一个adhoc查询被编译时缓存一个存根,在第二次编译后,存根用以取代全部计划。

控制为Ad Hoc混合负载设置的优化

启用选项方法有二:
1、

EXEC sp_configure 'optimize for ad hoc workloads'1;
RECONFIGURE;

2、 在SQL Server Management Studio界面,高级-属性-中启用。
邀月工作室

 编译计划存根

当 optimize for ad hoc workloads启用时,SQL Server缓存的存根仅仅大约300字节,并不包含查询计划的任何部分。它基本上仅仅是一个容器,以保持跟踪某一特殊的查询的前次编译。
这个存根包含了全部的缓存键和一个指向实际查询文本的指针。这个存根被存在SQL Manager 缓存。该存根的usecounts值始终是1,因为从来不会重用。

当生成编译计划存根的一个查询或批处理被重新编译时,这个存根被全编译计划代替。初始,usecounts被设置为1,因为不确定前一个查询是否与执行计划完全精确相同。

我们看一个例子:

EXEC sp_configure 'optimize for ad hoc workloads'1;
RECONFIGURE;
GO
USE Northwind2;
DBCC FREEPROCCACHE;
GO
SELECT * FROM Orders WHERE CustomerID = 'HANAR';
GO
SELECT usecounts, cacheobjtype, objtype, [text]
FROM sys.dm_exec_cached_plans P
        
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype LIKE 'Compiled Plan%'
        
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO
SELECT * FROM Orders WHERE CustomerID = 'HANAR';
GO
SELECT usecounts, cacheobjtype, objtype, [text]
FROM sys.dm_exec_cached_plans P
        
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype LIKE 'Compiled Plan%'
        
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO

邀月工作室
邀月工作室
如果关闭选项,执行:

EXEC sp_configure 'optimize for ad hoc workloads'1;
RECONFIGURE;
GO

简单参数化(Simple Parameterization)

 对于确定的查询,SQL Server能够决定是否需要把一个或多个常量参数化,此时,遵循相同基本模板的序列查询能够使用相同的计划。例如对于下列查询使用相同的计划:
SELECT FirstName, LastName, Title FROM Employees
WHERE EmployeeID = 6;
SELECT FirstName, LastName, Title FROM Employees
WHERE EmployeeID = 2;
SQL Server 在内部参数化这两个参数如下:
SELECT FirstName, LastName, Title FROM Employees
WHERE EmployeeID = @1;

 USE Northwind2
GO
DBCC FREEPROCCACHE;
GO
SELECT FirstName, LastName, Title FROM Employees WHERE EmployeeID = 6;
GO
SELECT FirstName, LastName, Title FROM Employees WHERE EmployeeID = 2;
GO
SELECT usecounts, cacheobjtype, objtype, [text]
FROM sys.dm_exec_cached_plans P
        
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = 'Compiled Plan'
        
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO

 查询结果类似如下:
邀月工作室

 你应该注意到两个独立的查询由于不同的常量作为临时查询得到了缓存。然而,这些仅仅被考虑为shell queries(盒子查询),它的缓存仅仅使得(在以后相同常量的精准查询而可能被重用时)查找查询的参数化版本容易一些。这个shell查询不包含全部查询计划,而仅仅在相关预备计划中有一个指向全部计划的指针。

注意:不要把shell查询和计划存根混淆。一个shell查询包含查询的完整文本,使用至少16K内存。Shell查询仅仅被SQL Server认为可参数化的计划创建。而计划存根(plan stub),仅仅在内存中使用200字节,为不可参数化的、临时查询所创建,并且仅仅当optimize for ad hoc workloads选项设置为时生效。

上图中,注意第三行,objtype为Prepared,注意useCounts为2或4,意味着,一个查询被重用了两次或四次。

默认情况下,SQL Server对于决定参数自动化是非常保守的。仅仅当查询模板被考虑为安全时才会自动参数化。如果即便实际参数值变化时,一个查询计划也不改变,那么,这个模板是安全的。这个安全原则确保参数化不会消弱查询的性能。上面查询中Employee表有一个惟一的索引,因此任何使用相等比较式的EmployeeID,不会有两行。在惟一索引中使用seek是非常有用的,无论实际值如何。

然而,考虑到查询可能是一个不等比较式,或一个不惟一的列的相等比较式时。这种情况下,一些实际查询值会返回多行,或没有行,或一行。因此,一个查询是否最好的计划,取决于查询使用的值,是否被认为是安全的,是否参数化。这是整个查询优化的核心。

除了需求一个查询模板仅仅一个可能的计划外,还有许多查询结构不允许简单参数化,如下:
1、JOIN

2、BLUK INSERT

3、IN 列表

4、UNION

5、INTO

6、FOR BROWSER

7、OPTION<query hints>

8、DISTINCT

9、TOP

10、WAITFOR语句

11、GROUP BY,HAVING,COMPUTE

12、全文谓词

13、序列化(subqueies)

14、FROM子句(Select语句含有表变量方法或全文表或OPENROWSET或OPENXML或OPENQUERY或OPENDATASOURCE

15、来自于<>比较谓词

简单参数化在使用下列结构的修改语句时了民被禁用:
1、带from子句的Delete/update

2、带(含变量的)set子句的Update

 ■强制参数化(Forced Parameterization)

 如果你的应用程序使用相同的查询,使用相同的计划明显会改善性能,但却没有自动参数化。或SQL Server出于安全考虑或使用了禁止的结构而没有采用参数化。SQL Server 2008提供了一种替代方案:一个数据库选项(Parameterization forced)

 ALTER DATABASE <database_name> SET PARAMETERIZATION FORCED;
该选项启用时,SQL Server将常量视作参数,有一些例外:
1、INSERT...EXECUTE语句

2、存储过程、触发器、或用户自定义函数内的语句。SQL Server已经为这些程序重用查询计划。

3、在客户端已经参数化的预备语句

4、包含XQuery方法调用的语句(Statements that contain XQuery method calls, where the method appears in a context where its arguments would typically be parameterized, such as a WHERE clause. If the method appears in a context where its arguments would not be parameterized, the rest of the statement is parameterized.)

5、T-SQL游标中的语句(API游标内部的Select语句被参数化)

6、已经被废弃的查询结构

7、任何运行在(ANSI_PADDING or ANSI_NULLS设置为Off的)上下文的任何语句

8、包含超过2097个Literals(直接常量)的语句

9、引用变量,如Where T.col2>=@p

10、包含RECOMPILE查询暗示的语句

11、包含一个COMPUTE子句的语句

12、包含一个WHERE CURRENT OF的子句

你需要谨慎为数据库设置这个选项,因为在优化期间所有的常量都参数化,那么频繁重用已经重用的计划将会导致性能急剧下降。

 

下文将继续关注简单参数化和预查询(Prepared Quries)

posted @ 2010-07-01 23:18  邀月  阅读(1598)  评论(0编辑  收藏  举报