直接查sys.dm_exec_query_stats和sys.dm_db_missing_index_details比profiler更快轻量;前者通过平均逻辑读、cpu及执行次数定位反复慢查询,后者提供缺失索引建议但需结合实际条件验证。

直接看 sys.dm_exec_query_stats 和 sys.dm_db_missing_index_details,比开 Profiler 更快、更轻量,且能覆盖历史缓存的执行计划。
查慢查询:从 sys.dm_exec_query_stats 提取高耗时语句
这个 DMV 保存了已缓存执行计划的聚合统计,是定位“反复慢”的第一站。关键不是看单次 Duration,而是看平均逻辑读 + 平均 CPU + 执行次数的组合。
-
total_logical_reads / execution_count> 1000 表示每次扫描大量数据页,大概率缺索引或走了全表扫描 -
total_elapsed_time / execution_count> 1000(毫秒)且execution_count≥ 5,说明该语句稳定地慢,不是偶发抖动 - 用
query_hash去重,避免同一条语句不同参数被当多条;再用sql_handle关联sys.dm_exec_sql_text()拿出原始 SQL - 别只盯着
Duration—— 网络延迟、锁等待都会拉长它,而logical_reads和cpu_time更反映语句自身效率
查缺失索引:用 sys.dm_db_missing_index_* 系列视图
SQL Server 会基于查询优化器的估算,主动记录“如果建了某个索引,本可节省多少 I/O”。但它不保证 100% 准确,也不代表必须建——得结合实际 WHERE/JOIN 条件和数据分布判断。
-
sys.dm_db_missing_index_details给出建议的列顺序:equality_columns(= 或 IN)、inequality_columns(>、included_columns(SELECT 中要覆盖的非键列) -
sys.dm_db_missing_index_group_stats的avg_total_user_cost×user_seeks是预估收益总和,值越大越值得优先评估 - 注意:这些视图只记录自上次服务重启/索引重建后的建议;如果 DBA 刚手动建了一批索引,视图可能清空或滞后
- 警惕“重复建议”——多个相似查询可能触发几乎一样的缺失索引提示,合并设计更高效,别一股脑建十个单列索引
关联分析:把慢查询和缺失索引线索串起来
光看各自输出容易误判。比如一条慢查询的 WHERE 条件是 Status = 'Active' AND CreatedDate > '2025-01-01',而缺失索引建议只提了 Status,那大概率是 CreatedDate 上没合适范围扫描能力,需要复合索引。
- 用
sys.dm_exec_query_plan(plan_handle)拿到执行计划 XML,搜索<missingindexes></missingindexes>节点,确认该慢查询是否真被这个缺失索引覆盖 - 检查
sys.dm_exec_query_stats中对应语句的last_execution_time是否在缺失索引视图的last_user_seek之后——如果不是,说明建议可能过期 - 对高频慢查询,优先验证缺失索引能否降低
logical_reads;若建完后 reads 没降,可能是统计信息过旧,先跑UPDATE STATISTICS
真正难的不是查出哪条慢、哪个索引缺,而是判断“这个索引建了会不会让其他写操作变卡”,或者“这个缺失索引建议其实已被某个宽索引覆盖”。上线前一定在测试库用真实负载压测,别只看 DMV 输出就拍板。










