2011-08-19 88 views
5

我们最近出现了一个性能问题,通过执行DBCC freeproccache解决了这个问题......现在,我们有更多的问题要回答;DBCC freeproccache?

  • 什么让过程缓存过期?
  • 如果索引或统计数据过期,为什么查询没有 重新编译自己?
  • 将DBCC freeproccache安排为JOB是否是一种很好的做法?
  • 有没有一种方法来识别潜在的过期查询计划?
  • 有没有一种方法来识别有问题的查询?

任何帮助表示赞赏!

+0

请确定您正在使用的SQL Server版本,例如[tag:sql-server-2005],[tag:sql-server-2008] ... –

+2

所有'DBCC freeproccache'确实都是空的过程缓存。它不会导致统计数据更新。相反,如果统计数据得到自动更新,那么计划将被重新编译。我假设你有一个参数嗅探问题,查询缓存中的计划不适合所有可能的参数值。 –

+0

我在SQL Server 2005上! – user173552

回答

8

你的问题到处都是,所以我会尽力解决所有问题。过程缓存只有这么大。您的过程缓存可能已被填充了单次使用计划(这对统计数据没有影响,但统计数据可能会影响计划缓存)。您可以在Kimberly Tripp的博客文章“Plan cache and optimizing for adhoc workloads”中阅读关于一次性使用计划的大量详细信息 - 包括对sys.dm_exec_cached_plans的查询,这将有助于确定缓存中何时填充大量一次性计划。正如她所建议的那样,您可以通过针对ad hoc工作负载进行优化来阻止这种膨胀。如果您经常需要这样做,我会说将freeproccache安排为工作是一种创可贴,而不是解决方案。

为了清除“坏”计划,首先您需要确定“坏”计划。这可能是一个超过一定规模和/或在一段时间内未执行的计划,或者是由长时间运行的查询等标识的。不幸的是,识别参数受害者的计划并不容易除非您已经知道受影响的查询或查询,否则可以进行嗅探。让我们假设你想找到尚未一个多星期运行缓存中最早的计划:

;WITH x AS 
(
    SELECT TOP 10 
     qs.[sql_handle], qs.plan_handle, 
     txs = qs.statement_start_offset, 
     txe = qs.statement_end_offset, 
     [size] = cp.size_in_bytes, 
     [uses] = SUM(cp.usecounts), 
     [last] = MAX(qs.last_execution_time) 
    FROM 
     sys.dm_exec_query_stats AS qs 
    INNER JOIN 
     sys.dm_exec_cached_plans AS cp 
     ON qs.plan_handle = cp.plan_handle 
    WHERE 
     qs.last_execution_time < DATEADD(DAY, -7, CURRENT_TIMESTAMP) 
    GROUP BY 
     qs.[sql_handle], qs.plan_handle, cp.size_in_bytes, 
     qs.statement_start_offset, qs.statement_end_offset 
    ORDER BY 
     [size] DESC 
) 
SELECT 
    x.plan_handle, 
    size, uses, [last], 
    [statement] = COALESCE(NULLIF(
     SUBSTRING(t.[text], x.txs/2, 
      CASE WHEN x.txe = -1 THEN 0 ELSE (x.txe - x.txs)/2 END 
     ), ''), t.[text]) 
FROM x 
CROSS APPLY sys.dm_exec_sql_text(x.[sql_handle]) AS t; 

现在,你需要确认你真的想清楚了这个计划。例如,如果您将该查询视为明天首席执行官可能会执行的操作,则最好将其留在那里。如果你想清除计划,可以说直接清除:

DBCC FREEPROCCACHE([paste plan handle from above query here]); 

这听起来似乎比运行DBCC FREEPROCCACHE全球更多的工作,但如果你有很多良好计划在缓存中,它肯定会对整个用户更好。

不过,这听起来像是一个创可贴。如果你的缓存充斥着垃圾,并且性能直到你释放缓存,你需要在架构上查看更高的层次,查询是如何提交的等等。这是我期望从LINQ2SQL的第一次迭代,它将缓存每个字符串参数的查询计划版本,该版本的长度不同。所以如果你有一个'1月'的参数,你会得到一个不同于'2月'的参数的计划,因为它会将数据类型定义为VARCHAR(7)VARCHAR(8)。很确定,行为是固定的,但我对您的环境/应用程序不够了解,无法确切知道在哪里寻找“坏主意”。

+0

忽略对临时工作负载的优化 - 这是在SQL Server 2008中引入的。 –