我一直在阅读有关Kimberly Tripp的一些有关SQL Server计划缓存的精彩文章,例如:http : //www.sqlskills.com/blogs/kimberly/plan-cache-and-optimizing-for-adhoc-workloads/
为什么甚至有“针对临时工作负载进行优化”的选项?这不应该一直都在吗?无论开发人员是否在使用即席SQL,为什么不在每个支持它的实例(SQL 2008+)上都启用此选项,从而减少缓存膨胀?
我一直在阅读有关Kimberly Tripp的一些有关SQL Server计划缓存的精彩文章,例如:http : //www.sqlskills.com/blogs/kimberly/plan-cache-and-optimizing-for-adhoc-workloads/
为什么甚至有“针对临时工作负载进行优化”的选项?这不应该一直都在吗?无论开发人员是否在使用即席SQL,为什么不在每个支持它的实例(SQL 2008+)上都启用此选项,从而减少缓存膨胀?
Answers:
SQL Server开发团队的工作原理是最不令人惊讶-因此,为了保持行为与以前的版本相同,SQL Server通常禁用新功能。
是的,针对临时工作负载进行优化可以极大地减少计划缓存膨胀-但始终要首先进行测试!
[编辑:Kalen Delaney讲述了一个有趣的轶事,她问她的一位Microsoft工程师朋友,是否在某些情况下不适合启用此功能。他几天后回来说-想象一个应用程序具有很多不同的查询,而每个查询总共运行两次。那么这可能是不合适的。可以说没有那么多的应用!]
[编辑:如果您的大多数查询执行了一次以上(不完全是两次);这可能是不合适的。一般规则是,如果数据库上有许多一次性使用的临时查询,则将其关闭;但是,仍然没有那么多的应用程序。]
以下是一些小的代码,可以帮助您确定“ 针对临时工作负载的开/关优化切换”是否有用。我们通常会在内部服务器和客户端服务器的运行状况检查中进行检查。
这是为了让最安全的选择,由布拉德描述以及这里和格伦·贝里在这里。
--- for 2008 and up .. Optimize ad-hoc for workload
IF EXISTS (
-- this is for 2008 and up
SELECT 1
FROM sys.configurations
WHERE NAME = 'optimize for ad hoc workloads'
)
BEGIN
DECLARE @AdHocSizeInMB DECIMAL(14, 2)
,@TotalSizeInMB DECIMAL(14, 2)
,@ObjType NVARCHAR(34)
SELECT @AdHocSizeInMB = SUM(CAST((
CASE
WHEN usecounts = 1
AND LOWER(objtype) = 'adhoc'
THEN size_in_bytes
ELSE 0
END
) AS DECIMAL(14, 2))) / 1048576
,@TotalSizeInMB = SUM(CAST(size_in_bytes AS DECIMAL(14, 2))) / 1048576
FROM sys.dm_exec_cached_plans
SELECT 'SQL Server Configuration' AS GROUP_TYPE
,' Total cache plan size (MB): ' + cast(@TotalSizeInMB AS VARCHAR(max)) + '. Current memory occupied by adhoc plans only used once (MB):' + cast(@AdHocSizeInMB AS VARCHAR(max)) + '. Percentage of total cache plan occupied by adhoc plans only used once :' + cast(CAST((@AdHocSizeInMB / @TotalSizeInMB) * 100 AS DECIMAL(14, 2)) AS VARCHAR(max)) + '%' + ' ' AS COMMENTS
,' ' + CASE
WHEN @AdHocSizeInMB > 200
OR ((@AdHocSizeInMB / @TotalSizeInMB) * 100) > 25 -- 200MB or > 25%
THEN 'Switch on Optimize for ad hoc workloads as it will make a significant difference. Ref: http://sqlserverperformance.idera.com/memory/optimize-ad-hoc-workloads-option-sql-server-2008/. http://www.sqlskills.com/blogs/kimberly/post/procedure-cache-and-optimizing-for-adhoc-workloads.aspx'
ELSE 'Setting Optimize for ad hoc workloads will make little difference !!'
END + ' ' AS RECOMMENDATIONS
END
启用“ 优化临时工作负载 ”选项时,您将导致第二次运行的临时查询的运行速度与第一次运行一样慢,因为您将编译执行计划并提取相同的数据(没有缓存)的前2次。
这可能没什么大不了的,但是在测试查询时您会注意到它。
那么,如果没有启用此选项并且缓存了1-Off Ad-Hoc查询,现在该怎么办?
由于引入了此优化功能,因此还更新了缓存管理算法。
Kimberly Tripp的文章还引用了Kalen Delaney关于此算法更改的帖子。
她最好的解释是:
所做的更改实际上将计算计划缓存大小,在该大小下,SQL Server会意识到存在内存压力,它将开始从缓存中删除计划。要删除的计划是尚未重用的廉价计划,这是一件好事。
这意味着当您需要释放资源时,那些讨厌的一次性计划将是第一个。
“ 当SQL Server在必要时删除未使用的计划时,为什么我们需要'针对临时工作负载进行优化? ”
我的答案是,如果您经常有大量的动态SQL生成非参数化广告的内容-hoc查询,那么启用此功能非常有意义。
您要避免对系统资源造成压力,以免在用完最大缓存内存空间后强制删除缓存计划/数据。
这是我写的一个查询,用于向您显示当前已缓存了多少个临时计划以及它们正在消耗多少磁盘空间(结果将全天变化-因此请在负载很重的时间进行测试):
--Great query for making the argument to use "Optimize for Ad Hoc Workloads":
SELECT S.CacheType, S.Avg_Use, S.Avg_Multi_Use,
S.Total_Plan_3orMore_Use, S.Total_Plan_2_Use, S.Total_Plan_1_Use, S.Total_Plan,
CAST( (S.Total_Plan_1_Use * 1.0 / S.Total_Plan) as Decimal(18,2) )[Pct_Plan_1_Use],
S.Total_MB_1_Use, S.Total_MB,
CAST( (S.Total_MB_1_Use * 1.0 / S.Total_MB ) as Decimal(18,2) )[Pct_MB_1_Use]
FROM
(
SELECT CP.objtype[CacheType],
COUNT(*)[Total_Plan],
SUM(CASE WHEN CP.usecounts > 2 THEN 1 ELSE 0 END)[Total_Plan_3orMore_Use],
SUM(CASE WHEN CP.usecounts = 2 THEN 1 ELSE 0 END)[Total_Plan_2_Use],
SUM(CASE WHEN CP.usecounts = 1 THEN 1 ELSE 0 END)[Total_Plan_1_Use],
CAST((SUM(CP.size_in_bytes * 1.0) / 1024 / 1024) as Decimal(12,2) )[Total_MB],
CAST((SUM(CASE WHEN CP.usecounts = 1 THEN (CP.size_in_bytes * 1.0) ELSE 0 END)
/ 1024 / 1024) as Decimal(18,2) )[Total_MB_1_Use],
CAST(AVG(CP.usecounts * 1.0) as Decimal(12,2))[Avg_Use],
CAST(AVG(CASE WHEN CP.usecounts > 1 THEN (CP.usecounts * 1.0)
ELSE NULL END) as Decimal(12,2))[Avg_Multi_Use]
FROM sys.dm_exec_cached_plans as CP
GROUP BY CP.objtype
) AS S
ORDER BY S.CacheType
我不会说“ 如果您拥有X MB ” 或 “ 如果X%的Ad Hoc是一次性的 ”,则将其打开。
它不影响Sproc,触发器,视图或参数化/准备的SQL,仅影响即席查询。
我个人的建议是仅在您的Prod环境中打开电源,但考虑在您的Dev环境中将其关闭。
我之所以只说说Dev,是因为如果您要优化一个需要花一分钟或更长时间才能运行的查询,那么您就不想运行3次,否则您可能看不到它被缓存的速度如何- 每一次一次编辑即可找到最佳的优化设计。
如果您的工作不涉及一整天的工作,那么请发疯并要求您的DBA在任何地方打开它。
“为什么不使用...。”在进行一些性能调查的过程中,在观察资源利用率的同时,几乎实时地将计划从计划缓存中拉出。“针对即席工作负载进行优化”可能会破坏这种情况,因为即席存根计划在查询缓存时不会返回计划。在这种情况下,如果无法通过其他方式识别查询和计划,则可以出于调查目的而再次打开或关闭该设置。请注意,设置的更改会影响从此刻开始编译的查询。另外,每当更改“服务器”属性时,请检查相同版本的非生产实例,以确认更改是否将刷新计划缓存。我个人讨厌对此感到惊讶。(例如,在服务器级别更改maxdop通常会刷新计划缓存,
“已编译的计划存根没有与之关联的执行计划,查询计划句柄将不会返回XML Showplan。” http://technet.microsoft.com/zh-CN/library/cc645587.aspx