定位引发Azure SQL高CPU占用的重复查询调用来源
追踪Azure SQL高CPU查询的来源及优化建议
一、应用层注入来源标识(最直接方案)
- 在应用的数据库操作入口(如页面初始化、接口方法),执行会话上下文设置,传入来源标识:
EXEC sp_set_session_context N'CallerSource', N'ProductListPage'; - SQL端可通过
SESSION_CONTEXT(N'CallerSource')获取该标识,结合后续的追踪工具,直接关联到调用页面/接口。
二、Azure SQL内置工具追踪
1. 扩展事件(Extended Events)
- 创建针对目标查询的事件会话,捕获
sql_statement_completed事件,同时勾选session_context、client_app_name、client_hostname等字段。 - 设置过滤条件匹配目标查询的特征文本(如
SELECT clmns.name AS [Name]),只捕获该查询的执行记录,从中提取来源信息。
2. Query Store
- 在Query Store中通过查询文本匹配找到目标查询,查看其执行历史中的
session_id。 - 关联
sys.dm_exec_sessions视图获取program_name、host_name等信息;若已注入会话上下文,可通过sys.dm_exec_session_context查询CallerSource的值。
3. DMVs实时查询
- 先通过
sys.dm_exec_query_stats定位目标查询的sql_handle:SELECT sql_handle, execution_count FROM sys.dm_exec_query_stats CROSS APPLY sys.dm_exec_sql_text(sql_handle) WHERE text LIKE '%SELECT clmns.name AS [Name]%' - 再关联会话视图获取来源标识:
SELECT s.session_id, s.program_name, sc.value AS CallerSource FROM sys.dm_exec_sessions s JOIN sys.dm_exec_session_context sc ON s.session_id = sc.session_id WHERE sc.key = N'CallerSource'
三、应用层日志拦截
- 使用AOP框架(如.NET AspectCore、Java Spring AOP)拦截所有数据库操作方法,自动记录调用来源(页面/接口名)、查询文本、参数到应用日志。
- 若使用ORM(如Entity Framework),可拦截
DbCommand执行事件,在查询文本前添加来源注释(如-- Source: CheckoutPage),SQL端追踪记录会直接显示来源。
四、临时应急方案
- 找到应用中生成该查询的代码位置,给不同调用处的查询添加唯一注释标识:
-- From: UserProfilePage SELECT clmns.name AS [Name], ... - 通过SQL执行日志或扩展事件,根据注释区分调用来源。
五、针对该查询的优化建议
- 该查询是读取系统表获取列元数据,大概率是ORM框架自动生成的元数据查询。开启ORM的元数据缓存(如EF的
ModelCacheKey),避免重复执行。 - 若无法缓存,可将查询结果缓存到应用层(如Redis、内存缓存),减少对SQL的直接调用。
内容的提问来源于stack exchange,提问作者Core IP
相关产品推荐
相关产品推荐

