【问题标题】:Extracting data from SQL Server's XML execution plan从 SQL Server 的 XML 执行计划中提取数据
【发布时间】:2013-11-07 22:44:45
【问题描述】:

我的最终目标是从缓存的执行计划中自动提取所有引用的列。这将帮助我们跟踪我们计划的 SSRS 报告集使用的所有列。

感兴趣的 XML 数据如下所示:

<ColumnReference Database="[AdventureWorksDW2012]" Schema="[dbo]" Table="[DimCustomer]"  Alias="[dC]" Column="HouseOwnerFlag" />

我想将数据库、架构、表、别名和列值存储在一个表中。

但是,为了概念验证,我进行了一个简单的查询,并将完整执行计划的以下部分复制到下面的 TSQL 代码中:

DECLARE @myDoc xml;
SET     @myDoc = '<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"  Version="1.2" Build="11.0.3381.0"  TEST="1">
    <BatchSequence>
      <Batch>
        <Statements>
          <StmtSimple StatementText="SELECT ... &#xD;&#xA;" StatementId="1" StatementCompId="1" ThereIsMoreHere="..." >
            <StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="true" ThereIsMoreHere="..." />
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>';

SELECT StatementId = @myDoc.value('(/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/@StatementId)[1]', 'int');
SELECT StatementId = @myDoc.value('(/ShowPlanXML/@TEST)[1]',                                     'int');

两个 SELECT 语句都返回 NULL。这里有什么问题?我觉得我正在慢慢失明。 这是针对 SQL Server 2012 SP1 Developers 版本执行的。

【问题讨论】:

  • 我认为您在层次结构中遗漏了“批次”。
  • 已编辑问题> 缺失的 /Batch/ 部分已编辑。接受答案中的 WITH 是要走的路!

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


【解决方案1】:

选择 SQL Server 执行计划中使用的所有列的最终目标已解决:

USE AdventureWorksDW2012

DBCC FREEPROCCACHE

SELECT dC.Gender, dc.HouseOwnerFlag, 
SUM(fIS.SalesAmount) AS SalesAmount 
FROM 
    dbo.DimCustomer dC INNER JOIN
    dbo.FactInternetSales fIS ON fIS.CustomerKey = dC.CustomerKey 
GROUP BY dC.Gender, dc.HouseOwnerFlag
ORDER BY dC.Gender, dc.HouseOwnerFlag
/*
query_hash          query_plan_hash
0x752B3F80E2DB426A  0xA15453A5C2D43765
*/

DECLARE @MyQ AS XML;

-- SELECT qstats.query_hash, query_plan_hash, qplan.query_plan AS [Query Plan],qtext.text 
SELECT @MyQ = qplan.query_plan 
 FROM sys.dm_exec_query_stats AS qstats 
  CROSS APPLY sys.dm_exec_query_plan(qstats.plan_handle) AS qplan 
  cross apply sys.dm_exec_sql_text(qstats.plan_handle) as qtext 
  where text like '% fIS %'
and query_plan_hash = 0xA15453A5C2D43765

SeLeCt @MyQ

;WITH xmlnamespaces (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT DISTINCT
    [Database] = x.value('(@Database)[1]', 'varchar(128)'),
    [Schema]   = x.value('(@Schema)[1]',   'varchar(128)'),
    [Table]    = x.value('(@Table)[1]',    'varchar(128)'),
    [Alias]    = x.value('(@Alias)[1]',    'varchar(128)'),
    [Column]   = x.value('(@Column)[1]',   'varchar(128)')
FROM   @MyQ.nodes('//ColumnReference') x1(x)

导致以下输出:

Database                  Schema Table            Alias Column
------------------------- ------ ---------------- ----- ----------------
NULL                      NULL   NULL             NULL  Expr1004
[AdventureWorksDW2012]    [dbo]  [DimCustomer]    [dC]  CustomerKey
[AdventureWorksDW2012]    [dbo]  [DimCustomer]    [dC]  Gender
[AdventureWorksDW2012]    [dbo]  [DimCustomer]    [dC]  HouseOwnerFlag
[AdventureWorksDW2012]    [dbo]  [FactInternetSal [fIS] CustomerKey
[AdventureWorksDW2012]    [dbo]  [FactInternetSal [fIS] SalesAmount

【讨论】:

    【解决方案2】:

    您需要为 xml 指定架构和默认命名空间:-

    with xmlnamespaces (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
    SELECT StatementId = @myDoc.value('(/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/@StatementId)[1]', 'int');
    
    with xmlnamespaces (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
    SELECT StatementId = @myDoc.value('(/ShowPlanXML/@TEST)[1]', 'int');
    

    【讨论】:

    • 不要忘记第一个查询中 xpath 中缺少的“批处理”
    • 或者您可以从 showplanxml 中去除命名空间定义(使 SELECT 更简单 - 但代码不那么健壮)
    • 为了捕捉丢失部分层次结构的可能情况,我使用了第二个 TEST 选择。这也不起作用,因为缺少 xmlnamespaces。我确实尝试删除 xmlnms,但没有丢失 /batch/ 部分,这没有帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多