• 【转】如何知道执行计划使用了那些统计信息


    出处:http://blogs.msdn.com/b/apgcdsd/archive/2012/11/28/10372470.aspx

    最近被一个客户问到了这样一个有趣的问题——执行计划在生成过程中使用了那些统计信息呢?针对这个问题,客户也做了一些研究,并给了我下面两篇博文作为切入点。

    1.      How to Find the Statistics Used to Compile an Execution Plan(http://sqlblog.com/blogs/paul_white/archive/2011/09/21/how-to-find-the-statistics-used-to-compile-an-execution-plan.aspx)

    2.      Statistics used in a cached query plan (http://blogfabiano.com/2012/07/03/statistics-used-in-a-cached-query-plan/)

     

    在查看了这两篇博文后,我把其中的奥秘摘出来跟大家分享一下。

    第一篇博文介绍了两个Trace Flag, 9204和9292。这两个Trace Flag是这样解释的:

     

    9204 – 打印出被加载的统计信息

    9292 – 打印出从元数据中得到的统计信息的头信息

     

    当然,要看到这些信息,我们还需要打开Trace Flag 3604才能让这些显示出来。以下面的脚本为例,

     

    USE Northwind

    GO

    DBCC FREEPROCCACHE()

    GO

    DBCC TRACEON(3604, 9292, 9204)

    GO

     

    SELECT Employees.FirstName, COUNT(Orders.OrderID)

    FROM Orders

    INNER JOIN Employees

          ON Orders.EmployeeID = Employees.EmployeeID

    WHERE Employees.FirstName = 'Steven'

    GROUP BY Employees.FirstName

    GO

     

    其返回结果为:

     

    Stats header loaded: DbName: Northwind, ObjName: Orders, IndexId: 4, ColumnName: EmployeeID, EmptyTable: FALSE

     

    Stats loaded: DbName: Northwind, ObjName: Orders, IndexId: 4, ColumnName: EmployeeID, EmptyTable: FALSE

     

    Stats header loaded: DbName: Northwind, ObjName: Orders, IndexId: 5, ColumnName: EmployeeID, EmptyTable: FALSE

     

    Stats header loaded: DbName: Northwind, ObjName: Employees, IndexId: 1, ColumnName: EmployeeID, EmptyTable: FALSE

     

    Stats loaded: DbName: Northwind, ObjName: Employees, IndexId: 1, ColumnName: EmployeeID, EmptyTable: FALSE

     

    Stats header loaded: DbName: Northwind, ObjName: Employees, IndexId: 4, ColumnName: FirstName, EmptyTable: FALSE

     

    Stats loaded: DbName: Northwind, ObjName: Employees, IndexId: 4, ColumnName: FirstName, EmptyTable: FALSE

     

    FirstName 

    ---------- -----------

    Steven     42

     

    从这个SELECT语句中,我们不难看出查询结果应该是员工Steven的First Name和这个员工有的所有的订单Order的数量。表Employees和Orders是用过EmployeeID来联系起来的。所以,在Employees.EmployeeID和Orders.EmployeeID上建立的索引上面的统计信息会被用来产生执行计划。当然除了他们,还应该有在字段Employees.FirstName上的统计信息,因为这个字段上没有索引存在,所以系统会在这里自动生成一个统计信息。

     

    需要注意的是,Trace Flag 9204和9292 只会在这个SELECT语句第一次被编译的时候打印出这些统计信息的记录。如果执行计划已经存在于缓存中,那么这些统计信息的记录则不会被打印出来。只有在用DBCC FREEPROCCACHE(plan_handle)清理了这条语句的缓存计划后,再次执行的时候才会再次被打印出来。

     

    第二篇博文介绍了另一个Trace Flag,8666。这个Trace Flag是这样解释的:

     

    8666 – 将Showplan的详细信息打印出来

     

    这个Trace Flag会将一些关于统计信息的内部信息显示出来。例如,

     

    USE Northwind

    GO

    DBCC FREEPROCCACHE()

    GO

    DBCC TRACEON(8666)

    GO

     

    SELECT Employees.FirstName, COUNT(Orders.OrderID)

    FROM Orders

    INNER JOIN Employees

          ON Orders.EmployeeID = Employees.EmployeeID

    WHERE Employees.FirstName = 'Steven'

    GROUP BY Employees.FirstName

    GO

     

     

    当你查看XML计划的时候,你可能会看到类似下面的信息。在第一行,我们可以看到有一个XML的标签叫做InternalInfo。再往下,我们会看到两个Recompile的标签,每一个标签对应这个SELECT语句中用到的一张表。在每一个Recompile标签下,又有两个ModTrackingInfo的标签,在这里统计信息被显示出来。在这个例子中,我们看到了四个统计信息的显示,可是实际被执行计划用到的只有三个(从前面介绍的方法可以得知)。也就是说,这里例举出的统计信息并不全都会被使用到,而是会被检查并判定是否被用于产生执行计划。

     

    <InternalInfoLockClassNoHint="0"LockClassIntLockHint="0"LockClassRCIsoHint="0">

      <OptmInfo>

         <FieldFieldName="m_iOptStage"FieldValue="1" />

         <FieldFieldName="m_cOptTask"FieldValue="382" />

         <FieldFieldName="m_ullAlgPmoSize"FieldValue="56" />

         <FieldFieldName="m_ullOptPmoSize"FieldValue="256" />

         <FieldFieldName="m_ullAlgTotalTime"FieldValue="514" />

         <FieldFieldName="m_ullAlgNetTime"FieldValue="514" />

         <FieldFieldName="m_ullOptTotalTime"FieldValue="51803" />

         <FieldFieldName="m_ullOptNetTime"FieldValue="37964" />

      </OptmInfo>

      <EnvColl>

         <Recompile>

            <FieldFieldName="wszDb"FieldValue="Northwind" />

            <FieldFieldName="wszSchema"FieldValue="dbo" />

            <FieldFieldName="wszTable"FieldValue="Employees" />

            <FieldFieldName="m_cRowCount"FieldValue="9" />

            <FieldFieldName="ullThreshold"FieldValue="500" />

            <FieldFieldName="wszReason"FieldValue="small table" />

            <FieldFieldName="m_fMissingStatsRecompile"FieldValue="0" />

            <FieldFieldName="m_fVisibleOutsideXact"FieldValue="1" />

            <FieldFieldName="m_dbId"FieldValue="7" />

            <FieldFieldName="m_mdObjectId"FieldValue="1977058079" />

            <FieldFieldName="m_mdBaseIndexId"FieldValue="1" />

            <FieldFieldName="m_cRowsetId"FieldValue="1" />

            <FieldFieldName="m_verStats"FieldValue="153" />

            <FieldFieldName="m_fAfterTriggerDelta"FieldValue="0" />

            <FieldFieldName="m_fInsteadOfDeltaPopulate"FieldValue="0" />

            <FieldFieldName="m_fInsteadOfDeltaInsideTrg"FieldValue="0" />

            <FieldFieldName="m_fIsSbQueue"FieldValue="0" />

               <ModTrackingInfo>

                  <FieldFieldName="wszStatName"FieldValue="PK_Employees" />

                  <FieldFieldName="wszColName"FieldValue="EmployeeID" />

                  <FieldFieldName="m_cCols"FieldValue="1" />

                  <FieldFieldName="m_idIS"FieldValue="1" />

                  <FieldFieldName="m_ullSnapShotModCtr"FieldValue="27" />

                  <FieldFieldName="m_ullRowCount"FieldValue="9" />

                  <FieldFieldName="ullThreshold"FieldValue="500" />

                  <FieldFieldName="wszReason"FieldValue="small table" />

               </ModTrackingInfo>

               <ModTrackingInfo>

                  <FieldFieldName="wszStatName"FieldValue="_WA_Sys_00000003_75D7831F" />

                  <FieldFieldName="wszColName"FieldValue="FirstName" />

                  <FieldFieldName="m_cCols"FieldValue="1" />

                  <FieldFieldName="m_idIS"FieldValue="4" />

                  <FieldFieldName="m_ullSnapShotModCtr"FieldValue="27" />

                  <FieldFieldName="m_ullRowCount"FieldValue="9" />

                  <FieldFieldName="ullThreshold"FieldValue="500" />

                  <FieldFieldName="wszReason"FieldValue="small table" />

               </ModTrackingInfo>

            </Recompile>

            <Recompile>

               <FieldFieldName="wszDb"FieldValue="Northwind" />

               <FieldFieldName="wszSchema"FieldValue="dbo" />

               <FieldFieldName="wszTable"FieldValue="Orders" />

               <FieldFieldName="m_cRowCount"FieldValue="830" />

               <FieldFieldName="ullThreshold"FieldValue="666" />

               <FieldFieldName="wszReason"FieldValue="heuristic" />

               <FieldFieldName="m_fMissingStatsRecompile"FieldValue="0" />

               <FieldFieldName="m_fVisibleOutsideXact"FieldValue="1" />

               <FieldFieldName="m_dbId"FieldValue="7" />

               <FieldFieldName="m_mdObjectId"FieldValue="21575115" />

               <FieldFieldName="m_mdBaseIndexId"FieldValue="1" />

               <FieldFieldName="m_cRowsetId"FieldValue="1" />

               <FieldFieldName="m_verStats"FieldValue="152" />

               <FieldFieldName="m_fAfterTriggerDelta"FieldValue="0" />

               <FieldFieldName="m_fInsteadOfDeltaPopulate"FieldValue="0" />

               <FieldFieldName="m_fInsteadOfDeltaInsideTrg"FieldValue="0" />

               <FieldFieldName="m_fIsSbQueue"FieldValue="0" />

               <ModTrackingInfo>

                  <FieldFieldName="wszStatName"FieldValue="EmployeeID" />

                  <FieldFieldName="wszColName"FieldValue="EmployeeID" />

                  <FieldFieldName="m_cCols"FieldValue="1" />

                  <FieldFieldName="m_idIS"FieldValue="4" />

                  <FieldFieldName="m_ullSnapShotModCtr"FieldValue="2490" />

                  <FieldFieldName="m_ullRowCount"FieldValue="830" />

                  <FieldFieldName="ullThreshold"FieldValue="666" />

                  <FieldFieldName="wszReason"FieldValue="heuristic" />

               </ModTrackingInfo>

               <ModTrackingInfo>

                  <FieldFieldName="wszStatName"FieldValue="EmployeesOrders" />

                  <FieldFieldName="wszColName"FieldValue="EmployeeID" />

                  <FieldFieldName="m_cCols"FieldValue="1" />

                  <FieldFieldName="m_idIS"FieldValue="5" />

                  <FieldFieldName="m_ullSnapShotModCtr"FieldValue="2490" />

                  <FieldFieldName="m_ullRowCount"FieldValue="830" />

                  <FieldFieldName="ullThreshold"FieldValue="666" />

                  <FieldFieldName="wszReason"FieldValue="heuristic" />

               </ModTrackingInfo>

            </Recompile>

        </EnvColl>

     </InternalInfo>

     

    另外,因为这些信息存在XML计划中,所以我们还可以通过下面的语句来直接把我们需要的信息截取出来。不过需要注意的是,运行下面的语句有时候会造成访问越界,所以请慎用!

     

    WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as p)

    SELECT qt.text AS SQLCommand,

          qp.query_plan,

          StatsUsed.XMLCol.value('@FieldValue','NVarChar(500)') AS StatsName

    FROM sys.dm_exec_cached_plans cp

          CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp

          CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) qt

          CROSS APPLY query_plan.nodes('//p:Field[@FieldName="wszStatName"]')StatsUsed(XMLCol)

    WHERE qt.text LIKE '%Steven%'

          AND qt.text NOT LIKE '%sys.%'

     

     

    综上所述,如果想要得知执行计划在生成过程中使用了那些统计信息,比较安全的做法是用Trace Flag 9204和9292。

  • 相关阅读:
    尝试用博客园写个人日记
    db4o能代替Hibernate吗?
    RSS是否能支持携带扩展的权重信息呢?
    log4view可以更清楚地看log文件,不知道咋用
    tafiti.com体验微软的silverlight
    推荐两个插件DPack, Resharper
    用美味书签的标签实现类似nextlib的知识管理
    进程通讯的多种方式
    多维角度聊聊结对编程
    在Windows下编译和.NET运行MemCached
  • 原文地址:https://www.cnblogs.com/SQLServer2012/p/2792847.html
Copyright © 2020-2023  润新知