如何使用TSQL过滤WHERE子句中的XML执行计划数据

时间:2013-07-10 13:44:26

标签: sql-server xml tsql sql-execution-plan

我在SO上看到过几个响应,其中TSQL语句使用XML数据类型的{.value或.exist方法(herehere)过滤XML数据。虽然我不熟悉这些方法的构造/语法,但我有一个更深层次的问题。

我试图查询一些缓存的执行计划数据,并在数据中搜索特定索引的引用,问题是我不知道XML中的哪个位置。现在我将XML CAST到NVARCHAR并使用LIKE(参见最后一行查询):

  DECLARE @IndexName NVARCHAR(100) = 'MyIndex'

    SELECT  OBJECT_NAME(objectid) AS procname, usecounts, query_plan
    FROM    sys.dm_exec_cached_plans cp
    CROSS   APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
    WHERE   objtype = 'Proc'
    AND     CAST(query_plan AS NVARCHAR(MAX)) LIKE '%' + @IndexName + '%'

所以这有效,但我得到了多余的结果。最后,我想获得索引搜索和扫描的结果,但是现在我还看到了索引被修改的行(例如,一般表更新的执行计划,因为索引也在更新)。

  1. 如何重新定义查询的最后一行以使用某种方式 通配符XML语法(并避免使用CASTing)?
  2. 如何优化该查询以仅返回具有 “IndexScan”的父节点
  3. 如何优化该查询以仅返回第1个项目 发现“RelOp”的祖先有一个名为“PhysicialOp”的属性 “索引寻求”的价值?
  4. 以下是一些简化的示例XML:

    <RelOp NodeId="13" PhysicalOp="Index Seek" LogicalOp="Index Seek">
        <OutputList>
            <ColumnReference Database="[MyDB]" Schema="[dbo]" Table="[Employees]" Column="EmployeeID" />
        </OutputList>
        <IndexScan Ordered="1" ScanDirection="FORWARD">
            <DefinedValues>
                <DefinedValue>
                    <ColumnReference Database="[MyDB]" Table="[Employees]" Column="EmployeeID" />
                </DefinedValue>
            </DefinedValues>
            <Object Database="[MyDB]" Schema="[dbo]" Table="[Employees]" Index="[MyIndex]" />
        </IndexScan>
    </RelOp>
    

1 个答案:

答案 0 :(得分:6)

declare @IndexName nvarchar(100) = '[MyIndex]';

with xmlnamespaces (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
select object_name(qp.objectid), 
       cp.usecounts,
       qp.query_plan
from sys.dm_exec_cached_plans as cp
  cross apply sys.dm_exec_query_plan(cp.plan_handle) as qp
where cp.objtype = 'Proc' and
      qp.query_plan.exist('//RelOp[
                                  @PhysicalOp = "Index Seek" and 
                                  IndexScan/Object/@Index = sql:variable("@IndexName")
                                  ]') = 1;

查询计划中的索引具有方括号,因此您需要在变量中包含该索引。

//RelOp深入搜索选择RelOp@PhysicalOp的所有Index Seek个节点,并且存在子节点IndexScan/Object {{1}你存储在变量中的是什么。