TSQL:查找查询分别导致过多的SQL编译和SQL重新编译


8

我想找出是什么导致性能监视器计数器中出现的高SQL编译(不是重新编译)。

这是我的看法:如果我看到许多SQl编译,则意味着由于以下原因,我们的系统上的查询未得到缓存:

  • 许多特别查询
  • 运行SQl不缓存的查询,例如:

    UPDATE table1 SET col1 ='字符串长于8000个字符...'WHERE key_column =一些整数

  • 计划正在超时并从缓存中删除,原因如下:缓存空间不足或计划使用时间不够长。

捕获捕获到探查器中的缓存插入的唯一方法是存储过程-> SP:CacheInserts,但它仅负责存储过程缓存。

所以我尝试了以下方法来获取即席查询:

SELECT [cp].[refcounts] -- when Refcounts becomes 0, plan is excluded from cache.
    , [cp].[usecounts] 
    , [cp].[objtype] 
    , st.[dbid] 
    , st.[objectid] 
    , st.[text] 
    , [qp].[query_plan] 
FROM sys.dm_exec_cached_plans cp     
CROSS APPLY sys.dm_exec_sql_text ( cp.plan_handle ) st     
CROSS APPLY sys.dm_exec_query_plan ( cp.plan_handle ) qp ;

我认为导致编译的查询应该是objtype = Adhoc的查询,但这也可能与重新编译有关。现在,我必须运行事件探查器,捕获导致重新编译的查询,然后从上面的列表中删除它。

我朝着正确的方向前进吗?

我可以使用一个查询来完成SQL编译而无需进行太多工作吗?

帮助我获得上述知识的资源:

http://social.msdn.microsoft.com/Forums/zh-CN/sqldatabaseengine/thread/954b4fba-3774-42e3-86e7-e5172abe0c83 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=143946 http: //technet.microsoft.com/zh-CN/library/cc966425(zh-cn).aspx
http://www.sqlservercentral.com/Forums/Topic914951-360-1.aspx

任何帮助都非常感谢。

Answers:


7

我不认为您可以通过简单的方式找到它,但是仍然有可能解决这个问题。Profiler提供了许多事件类类型,可用于分析查询的性能。启动一个新的探查器会话并检查以下事件:

Performance: Performance statistics
Stored Procedures: RPC:Completed
TSQL: SQL:BatchCompleted
TSQL: SQL: BatchStarting

选中“显示所有列”,然后选择“性能:仅性能统计事件”下的每一列。其余事件可以保留默认设置。

接下来,选择列过滤器,并按DatabaseName和/或LoginName / ApplicationName / HostName等进行过滤(如果知道)。目的是限制在Profiler中显示的行数,并仅专注于您的需求。

接下来,按运行,让它运行一段时间(只要需要2-3分钟)。分析主要在以下方面显示的结果:性能统计事件。

如果经常出现性能统计信息,则意味着查询计划是第一次缓存,从PlanCache编译,重新编译或逐出。据我所知,如果查询在计划缓存中没有查询计划,您将看到2行PerformanceStatistics事件,然后是SQL:BatchStarting,然后是SQL:BatchCompleted。这意味着查询计划首先被编译,缓存,然后查询开始并完成。

查看“性能统计信息”事件下的以下列:

SPID - ID of the session on which the event occurred. You can use it to identify the       
       row on SQL:BatchCompleted event which will display the SQL Query text and other  
       usefull information (Read/Writes, StartTime/EndTime)
Duration - Total time, in microseconds, spent during compilation.
EventSubClass - 0 = New batch SQL text that is not currently present in the cache.
                1 = Queries within a stored procedure have been compiled.
                2 = Queries within an ad hoc SQL statement have been compiled.
                3 = A cached query has been destroyed and the historical performance         
                    data associated with the plan is about to be destroyed.
                4 = A cached stored procedure has been removed from the cache and the  
                    historical performance data associated with it is about to be 
                    destroyed.

                5 = A cached trigger has been removed from the cache and the historical  
                    performance data associated with it is about to be destroyed.

考虑EventSubClass编号,您可以找出查询计划发生了什么并采取特定措施。此外,如果您被HostName,WindowsUser或Profiler跟踪中的其他信息所困扰,则可以向存储过程TSQL事件类中添加其他列。跟踪也可以存储在SQL表中,从而使分析更加轻松并且可自定义。这是一个更多描述性能统计事件类链接。


4

好吧,首先让我们看看高速缓存上是否有压力。

select bpool_visible from sys.dm_os_sys_info
go

将该数字乘以8得到K的内存。0-4G的75%+ 4G-64G的10%+ 5%的更多是计划缓存压力限制。如果达到此限制的75%,SQL Server将开始从缓存中清除计划。当将新的查询计划添加到缓存时,将发生清除,因此线程将暂停以进行此工作。可能导致计划被清除的第二件事是,如果计划数量超过哈希桶数量的4倍(哈希表将plan_handle映射到计划)。在32位系统上为10,000,在64位系统上为40,000。

select type, sum(pages_allocated_count) as pages_used from sys.dm_os_memory_objects 
where type in ('MEMOBJ_CACHESTOREOBJCP', 'MEMOBJ_CACHESTORESQLCP', 'MEMOBJ_CACHESTOREXPROC')
group by type
go

清除内容的决定不是取决于使用情况,而是取决于计划的成本,最便宜的计划首先被清除(生产成本,而不是执行成本)。如果您在上添加列original_costcurrent_cost查询,则可以看到此内容sys.dm_exec_cached_plans。临时计划从0开始,每次使用时增加1。发生缓存压力时,SQL Server从每个成本中减去一半,然后清除已达到0的那些。

如果您有很多临时SQL,请尝试:

exec sp_reconfigure 'optimize for ad hoc workloads', 1
go
reconfigure
go

在这种模式下,SQL Server第一次看到一个特定的SQL语句时,仅缓存一个大约300个字节的“存根”(正常查询计划最小为24k),其中包含一个散列和一个指向SQL文本的指针。如果再次执行,则随后将缓存整个计划。这不一定会减少编译本身,但会减轻计划缓存中的内存压力。

注意:此方法在2008年有效,而在2005年没有尝试过。

另一个技巧是

alter database ... set parameterization forced
go

这将导致SQL Server将常量视为参数,这有助于自动参数功能,该功能通常会缓存相似SQL语句的计划。除非您的服务器内存不足,否则临时SQL 应该缓存其查询计划,除非它可以精确地文本匹配,除非可以对其进行参数化,在这种情况下,它的行为更像是准备好的查询。


谢谢!我知道此“强制参数化”选项,但不敢使用它。在使用此功能时,我看到的唯一缺点是它将填满缓存。我对吗?
Manjot 2011年

3

您在此框中是否有许多经常运行的SQL Server作业?请注意,在2005年,不缓存代理作业查询,并且也可能导致缓存膨胀和sql编译。

查看重用次数少的计划的数量。那是你的罪魁祸首。

下面有关计划缓存的一些相关说明。

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Plan-cache-adhoc-workloads-and-clearing-the-single-use-plan-cache-bloat.aspx

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Clearing-the-cache-are-there-other-options.aspx


0

这种影响称为“查询计划污染”,其中许多类似的SQL查询生成单独的但等效的执行计划。

临时查询通过单独的解析而导致开销,但通常不会查询计划污染,因为它们的计划没有存储。对于仅具有一个参数的查询(在MS SQL Server下),这是不同的,这些将被视为参数化查询。

查询计划污染有一些典型的情况:

  • 仅具有一个硬编码文字参数的SQL查询(例如“选择ID,ID为1234的人的名字”)
  • 特别是与强制数据库存储查询计划的命令/存储过程一起使用时,例如在MSSQL下使用“ sp_prepexec”或“ sp_executesql”(我认为Oracle下的“立即执行”以类似的方式工作)
  • 部分参数化的查询,“硬编码”字面值有很大差异,例如“从SoccerMatches sm中的select *,其中sm.Date>?” 和sm.Date <?和HomeClubId = 5678和GuestClubId = 1234'。这些会由于参数而保存查询计划,但是会为每个更改的HomeClub或GuestClub创建一个新的查询计划(特别是因为日期/时间值是在许多DB API中引入参数的好机会,当查询由于本地日期不同而失败时)格式)。
  • 查询计划污染的另一个来源可能是诸如ADO.NET之类的框架,该框架缺少足够的驱动程序,并结合了string /(n)varchar值。一些实现/驱动程序会将参数大小设置为实际的字符串长度,从而为查询中的每个不同的字符串参数长度产生单独的查询计划。最佳实践似乎是使用最大字段大小(例如varchar(4000))或使用正确长度的驱动程序
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.