【问题标题】:How to get parameter values for dm_exec_sql_text如何获取 dm_exec_sql_text 的参数值
【发布时间】:2010-03-24 16:04:49
【问题描述】:

我正在运行以下语句来查看 sql server 中正在执行哪些查询:

select *
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle)
where r.database_id = DB_ID('<dbname>')

返回的sql文本是参数化的:

(@Parm0 int) select * from foo where foo_id = @Parm0

有没有办法获取语句使用的参数的值?或许可以加入另一个表?

【问题讨论】:

  • 需要多做一些工作才能把它弄出来,但如果我必须拥有它,它就可以工作。谢谢!
  • 您有没有找到解决方案?接受的答案似乎不起作用......

标签: sql-server sql-server-2005 sql-server-2008


【解决方案1】:

编辑:Remus 是正确的,这只会在查询计划第一次命中缓存时带出编译版本,而不是后续运行。

您应该能够从查询计划中获取参数,因为它包含最后使用的参数。修改代码:

select * 
from sys.dm_exec_requests r 
cross apply sys.dm_exec_query_plan(plan_handle) as qp
cross apply sys.dm_exec_sql_text(r.sql_handle) 
where r.database_id = DB_ID('<dbname>') 

您会发现查询计划的最后一列是 query_plan,这是您可以手动检查的查询计划的 xml 版本,XML 的底部是参数,或者如果您喜欢挑战,请使用 XML 解析和 XQuery拉出 ParameterList 标签

【讨论】:

  • 我认为这些是在计划生成期间嗅探到的参数,而不是最后使用的参数。
  • 你说得对,这是一匹母马,因为我没有看到其他 DMV 记录了简单/强制参数化对语句所做的事情
  • WRT “如果您喜欢挑战,请使用 XML Parsing...”,请参阅 blog post
【解决方案2】:

如果您可以帮助 sys.dm_exec_query_stats 的联接,则提供登录名、执行时间和查询作为最后事件文本的查询,但它可以工作

SELECT distinct
s.login_name,
qs.creation_time 
,SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
((CASE statement_end_offset
  WHEN -1 THEN DATALENGTH(st.text)
  ELSE qs.statement_end_offset END
  - qs.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_sessions S
LEFT JOIN sys.dm_exec_connections AS c ON S.session_id = c.session_id
,sys.dm_exec_query_stats QS --qs on c.most_recent_sql_handle = qs.sql_handle
OUTER APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE ST.text LIKE '%yourKeyWord%' and s.login_name <> 'NT SERVICE\SQLSERVERAGENT'
order by qs.creation_time desc

【讨论】:

  • 不知道为什么这个答案没有得到更多的爱,在我看来它比选择的答案更接近 - 你可以更容易地找到实际执行的查询。
【解决方案3】:

如果有人偶然发现此线程正在寻找合适的解决方案(遗憾的是其他答案缺乏),我发现了这个helpful post from mssqltips

我对查询进行了一些清理和调整,以实现这一点:

-- cleanup
IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
    DROP TABLE #compiledValue
GO

-- Prepare temp table #compiledValue
SELECT  
    OBJECT_NAME(est.objectid) ObjectName,
    DB_NAME(est.dbid) DBName,
    eqs.last_execution_time,
    est.text,
    (eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
    (IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
    TRY_CONVERT(XML, 
        SUBSTRING(etqp.query_plan,
            CHARINDEX('<ParameterList>',etqp.query_plan),
            CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params
INTO #compiledValue
FROM sys.dm_exec_query_stats eqs
     CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
     CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp

SELECT 
    cvalue.last_execution_time,
    cvalue.DBName,
    cvalue.ObjectName,
    SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
    pc.compiled.value('@Column', 'nvarchar(128)') AS Parameterlist,
    pc.compiled.value('@ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
FROM #compiledValue cvalue
OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
ORDER BY cvalue.last_execution_time DESC
GO

-- cleanup
DROP TABLE #compiledValue
GO

效果很好,每个参数都有自己的一行。

例如:

【讨论】:

    【解决方案4】:

    如果您使用的是 SQL Server 2012 或 Amazon RDS 之前的版本,其中 TRY_CONVERT 函数不存在,这是 Indigo 查询的变体。

    -- cleanup
    IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
        DROP TABLE #compiledValue
    GO
    
    -- Prepare temp table #compiledValue
    SELECT  
        OBJECT_NAME(est.objectid) ObjectName,
        DB_NAME(est.dbid) DBName,
        eqs.last_execution_time,
        est.text,
        (eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
        (IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
        --TRY_CONVERT(XML, 
        --    SUBSTRING(etqp.query_plan,
        --        CHARINDEX('<ParameterList>',etqp.query_plan),
        --        CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params,
        CASE
            WHEN CHARINDEX('<ParameterList>', etqp.query_plan) > 0
                THEN CONVERT(XML, 
                        SUBSTRING(etqp.query_plan, 
                            CHARINDEX('<ParameterList>', etqp.query_plan), 
                            CHARINDEX('</ParameterList>', etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>', etqp.query_plan) )) 
            ELSE NULL
        END AS statement_params
    INTO #compiledValue
    FROM sys.dm_exec_query_stats eqs
         CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
         CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp
    
    SELECT 
        cvalue.last_execution_time,
        cvalue.DBName,
        cvalue.ObjectName,
        SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
        pc.compiled.value('@Column', 'nvarchar(128)') AS Parameterlist,
        pc.compiled.value('@ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
    FROM #compiledValue cvalue
    OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
    WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
    ORDER BY cvalue.last_execution_time DESC
    GO
    
    -- cleanup
    DROP TABLE #compiledValue
    GO
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 2014-06-06
      • 2016-10-09
      • 2016-05-30
      • 1970-01-01
      • 2022-10-01
      相关资源
      最近更新 更多