最直接方式是查 sys.dm_exec_requests 和 sys.dm_exec_sql_text;需用 cross apply 关联 sql_handle 获取实际语句,筛选 status='running' 且 cpu_time>5000 毫秒的高 cpu 请求。

查 sys.dm_exec_requests 和 sys.dm_exec_sql_text 是最直接的方式
SQL Server 本身不提供“CPU占用语句”的现成视图,但组合动态管理视图(DMV)可以实时抓取正在运行且消耗 CPU 高的语句。核心逻辑是:找 status = 'running' 且 cpu_time > 0 的请求,再关联取出 SQL 文本。
常见错误是只查 sys.dm_exec_sessions 或漏掉 CROSS APPLY 关联文本——这会导致看到 SPID 却看不到实际语句。
- 必须用
CROSS APPLY sys.dm_exec_sql_text(sql_handle)获取语句内容,sql_handle来自sys.dm_exec_requests -
cpu_time单位是毫秒,建议过滤cpu_time > 5000(即 5 秒以上),避免噪音 - 注意权限:需要
VIEW SERVER STATE权限,否则 DMV 返回空结果 - 不要在生产环境长期运行
SELECT *查询这些 DMV,尤其带sys.dm_exec_sql_text,可能引发轻微性能抖动
建一个轻量级监控视图,避免每次手写 JOIN
你可以创建一个用户视图封装常用字段,比如 session_id、start_time、cpu_time、command、text,方便 DBA 或开发快速排查。
示例定义(可直接执行):
CREATE VIEW dbo.v_high_cpu_queries AS
SELECT
r.session_id,
r.start_time,
r.cpu_time,
r.command,
t.text AS sql_text,
r.wait_type,
r.blocking_session_id
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.status = 'running' AND r.cpu_time > 5000;
这个视图不包含计算列或函数索引,所以查询开销低;但它不缓存历史数据,只反映“此刻正在跑”的高 CPU 请求。
- 别在视图里加
ORDER BY或TOP,会限制后续查询灵活性 - 如果想看最近 1 分钟内累计 CPU 最高的语句,得换用
sys.dm_exec_query_stats+query_hash,那是另一类分析场景 - SQL Server 2019 支持
sys.dm_exec_input_buffer查语句开头,但对长 SQL 不够全,仍推荐sys.dm_exec_sql_text
sys.dm_exec_query_stats 适合分析“历史高频高 CPU”语句
当问题不是“当前卡住”,而是“某类语句反复吃 CPU”,就得看查询计划缓存里的聚合统计。这时 sys.dm_exec_query_stats 更合适,它按 query_hash 聚合,自带 total_worker_time(等价于总 CPU 时间)。
关键点在于:它不反映实时运行态,而是“自上次编译以来”的累计值。所以不能用来 kill 当前会话,但能定位慢模板。
- 用
total_worker_time / execution_count算平均 CPU 消耗,比单看total_worker_time更有参考价值 - 必须
CROSS APPLY sys.dm_exec_sql_text(plan_handle)才能拿到语句,plan_handle是它的主键 - 缓存会被清空(如
DBCC FREEPROCCACHE、内存压力大时),所以不是永久记录 - SQL Server 2019 中,
query_hash对参数化语句稳定,但对硬编码值或拼接 SQL 可能分裂成多个 hash
容易被忽略的干扰项:并行执行、等待类型和隐式转换
看到 cpu_time 高,不等于语句本身写得差。SQL Server 的 CPU 统计包含线程调度、排序哈希运算、甚至某些等待期间的伪占用(比如 SOS_SCHEDULER_YIELD)。真实瓶颈可能藏在别处。
-
wait_type = 'SOS_SCHEDULER_YIELD'高频出现,往往说明 CPU 真饱和了,不是语句问题而是资源不足 - 并行计划中,
cpu_time是所有线程之和,可能远大于实际耗时(elapsed_time),别直接拿它对比单线程语句 - 检查执行计划里是否有
CONVERT_IMPLICIT:隐式类型转换常导致索引失效+大量 CPU 解析,但 DMV 里不直接体现,需结合sys.dm_exec_query_plan - 系统 SPID(
session_id )也可能占 CPU,比如 <code>LOG WRITER或LAZY WRITER,这类不应干预
真正要盯的是 user session(session_id >= 50)里那些 cpu_time > elapsed_time * 0.8 的请求——说明它真正在密集计算,而不是等 I/O 或锁。










