【问题标题】:Get Long Running Queries For Users Or Applications Queries获取用户或应用程序查询的长时间运行查询
【发布时间】:2020-06-15 19:28:33
【问题描述】:

我最近读到了这篇完美的文章:

How to Find Longest Running Query With Execution Plan – Interview Question of the Week #098

它返回系统调用查询(用于内部 SQL Server 工作)。

是否可以过滤这些查询并仅返回用户或应用程序调用查询?

谢谢。

【问题讨论】:

  • 您要根据什么条件准确过滤?什么是“应用调用查询”?

标签: sql-server performance sql-server-2016 dmv


【解决方案1】:

您已经成功了 1/2:您需要捕获有关正在运行的内容的历史信息。您在问题 sys.dm_exec_query_stats 中查询的是累积和聚合统计信息,这些统计信息不是由保证仍连接到服务器的会话/连接,以便您识别它来自何处。为了克服这个问题,您需要捕获历史信息。有很多方法可以做到这一点。我建议使用带有 tSQL 步骤的 SQL Server 代理作业。您需要按计划运行类似于以下查询的内容并将数据记录到历史表中。然后,您可以将 sql_handle 上的原始查询交叉应用或加入到您从 SQL Server 代理作业中保持最新的历史记录表中

select
    r.session_id,
    s.login_name,
    c.client_net_address,
    s.host_name,
    s.program_name,
    r.sql_handle,
    r.start_time
from sys.dm_exec_requests r
inner join sys.dm_exec_sessions s
on r.session_id = s.session_id
left join sys.dm_exec_connections c
on r.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st

因此,如果您有一个按计划运行的 SQL Server 代理作业,将上述查询结果发送到 DBA.dbo.QueryHistory,您可以将原始查询从 sqlauthority 更改为类似这样的内容,以获取与查询相关联的用户名:

SELECT TOP 10
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
ISNULL(s.total_elapsed_time / 1000 / NULLIF(s.execution_count, 0), 0) AS AvgElapsedTime,
s.creation_time AS LogCreatedOn,
ISNULL(s.execution_count / 1000 / NULLIF(DATEDIFF(s, s.creation_time, GETDATE()), 0), 0) AS FrequencyPerSec
,query_plan
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_query_plan( s.plan_handle ) u
CROSS APPLY sys.dm_exec_sql_text( s.plan_handle ) t
outer apply (
select top 1 login_name
from DBA.dbo.QueryHistory  QH
where QH.sql_handle = s.sql_handle
)
ORDER BY MaxElapsedTime DESC

【讨论】:

  • 谢谢,但我无法在服务器上运行 Job。我只能从DMVs查询
  • @Arian 您需要的历史信息目前无法从任何 DMV 获得。您需要构建某种流程来捕获它。如果 SQL Server 代理作业不是您可以在您的环境中使用的一种方法,您也可以使用扩展事件来做一些事情,或者甚至像触发器这样简单的事情,但您需要一些机制来捕获历史数据。
  • 原始脚本返回我需要的信息,但它包含系统查询
【解决方案2】:

我已修改查询以获取用户/应用程序调用查询。您可以从sys.dm_exec_sessions获取客户特定信息

SELECT TOP 10
ss.program_name, --Name of the client program
ss.host_name, -- Workstation of client session
ss.client_interface_name, -- Driver used by client to communicate
ss.login_name, -- Client login name
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
ISNULL(s.total_elapsed_time / 1000 / NULLIF(s.execution_count, 0), 0) AS AvgElapsedTime,
s.creation_time AS LogCreatedOn,
ISNULL(s.execution_count / 1000 / NULLIF(DATEDIFF(s, s.creation_time, GETDATE()), 0), 0) AS FrequencyPerSec
,query_plan

FROM sys.dm_exec_query_stats s
INNER JOIN sys.dm_exec_requests as r
on r.plan_handle = s.plan_handle
INNER JOIN sys.dm_exec_sessions AS ss
ON ss.session_id = r.session_id
CROSS APPLY sys.dm_exec_query_plan( s.plan_handle ) u
CROSS APPLY sys.dm_exec_sql_text( s.plan_handle ) t
WHERE ss.program_name is not null -- not internal session
ORDER BY MaxElapsedTime DESC

【讨论】:

  • 谢谢,但是这个查询没有为我返回任何东西。原始查询可以。我认为这是因为您的脚本返回实时查询并且不考虑查询历史
  • @Arian,是的。当我加入 sys.dm_exec_requests、sys.dm_exec_sessions 时,它是实时数据。
  • 抱歉,我想在系统启动后获得长时间运行的查询
【解决方案3】:

这是不可能的,现在没有 DMV 保存此信息。

顺便说一句,什么是“应用程序调用查询”?你指的是工作吗?

正如其他人已经写过的那样,您唯一的选择是将此信息与触发器、作业或外部应用程序一起保存。

【讨论】:

  • 谢谢。我的意思是从应用程序执行的用户查询
猜你喜欢
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多