SQLSERVER__EXPLAIN 常用分析案例。

目录


SQL Server 中的执行计划分析

SQL Server 没有 EXPLAIN 命令,但有更强大的执行计划分析工具。

一、SQL Server 执行计划查看方式

1. SET STATISTICS 系列命令(最常用)

sql 复制代码
-- 开启实际执行计划(显示执行时间和IO)
SET STATISTICS TIME ON;
SET STATISTICS IO ON;

-- 执行你的查询
SELECT * FROM Ware_WareHouseBill WHERE WareHouseBillCode = '3161-5';

-- 关闭统计信息
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

输出示例:

复制代码
SQL Server 执行时间:
   CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
表 'Ware_WareHouseBill'。扫描计数 1,逻辑读取 5 次,物理读取 0 次...

(1 行受影响)

2. SHOWPLAN 命令(显示预估执行计划)

sql 复制代码
-- 显示预估执行计划(不执行查询)
SET SHOWPLAN_XML ON;
GO
SELECT * FROM Ware_WareHouseBill WHERE WareHouseBillCode = '3161-5';
GO
SET SHOWPLAN_XML OFF;
sql 复制代码
-- 显示实际执行计划(执行查询)
SET STATISTICS XML ON;
GO
SELECT * FROM Ware_WareHouseBill WHERE WareHouseBillCode = '3161-5';
GO
SET STATISTICS XML OFF;

3. 使用系统函数获取执行计划

sql 复制代码
-- 获取查询的执行计划(SQL Server 2016+)
SELECT * 
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE st.text LIKE '%Ware_WareHouseBill%';

二、实际案例分析

案例1:分析你的视图查询

sql 复制代码
-- 开启统计信息
SET STATISTICS TIME ON;
SET STATISTICS IO ON;

-- 执行你的查询
SELECT * FROM
(
    SELECT
        a.WareHouseBill_Id, 
        a.WareHouseBillCode, 
        a.WareHouseBillType, 
        a.WareHouseDate,
        a.CreateDate, 
        a.CreateID, 
        a.Creator,
        a.Modifier, 
        a.ModifyDate, 
        a.ModifyID,
        a.WareHouseCode,
        a.SourceDocuments, 
        a.SUPPLIER_NO,
        a.Status,
        c.SGName,
        (
            SELECT COUNT(WareHouseBillList_Id) 
            FROM Ware_WareHouseBillList l 
            WHERE l.WareHouseBill_Id = a.WareHouseBill_Id 
                AND (l.CheckStatus = 2 OR l.CheckStatus = 0 OR l.CheckStatus IS NULL) 
                AND l.Status != 3 
        ) AS uCoun,
        (
            SELECT STRING_AGG(
                CAST(l.ProductCode + ',' + ISNULL(l.LotCode, '') AS VARCHAR(MAX)), 
                ';'
            ) 
            FROM Ware_WareHouseBillList l 
            WHERE l.WareHouseBill_Id = a.WareHouseBill_Id 
                AND (l.CheckStatus = 2 OR l.CheckStatus = 0 OR l.CheckStatus IS NULL) 
                AND l.Status != 3 
        ) AS Remark
    FROM Ware_WareHouseBill AS a
        LEFT JOIN Base_Supplier AS c ON a.SUPPLIER_NO = c.SGCode 
    WHERE a.Status = 1 OR a.Status = 2
) AS subquery 
WHERE uCoun > 0 
    OR WareHouseBillType LIKE 'source%';

SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

案例2:查看索引使用情况

sql 复制代码
-- 查看表的索引
EXEC sp_helpindex 'Ware_WareHouseBill';
EXEC sp_helpindex 'Ware_WareHouseBillList';
EXEC sp_helpindex 'Base_Supplier';

-- 查看索引使用统计
SELECT 
    OBJECT_NAME(s.object_id) AS TableName,
    i.name AS IndexName,
    i.type_desc,
    s.user_seeks,
    s.user_scans,
    s.user_lookups,
    s.user_updates
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
WHERE OBJECT_NAME(s.object_id) IN ('Ware_WareHouseBill', 'Ware_WareHouseBillList', 'Base_Supplier')
ORDER BY TableName, IndexName;

案例3:分析缺失索引

sql 复制代码
-- 查找缺失索引的建议
SELECT 
    migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) AS improvement_measure,
    mid.statement AS TableName,
    mid.equality_columns,
    mid.inequality_columns,
    mid.included_columns,
    migs.avg_total_user_cost,
    migs.avg_user_impact,
    migs.user_seeks,
    migs.user_scans
FROM sys.dm_db_missing_index_group_stats migs
INNER JOIN sys.dm_db_missing_index_groups mig ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE mid.database_id = DB_ID()
ORDER BY improvement_measure DESC;

案例4:查看正在运行的查询执行计划

sql 复制代码
-- 查看当前正在执行的查询及其执行计划
SELECT 
    r.session_id,
    r.cpu_time,
    r.total_elapsed_time,
    t.text AS SQL_Text,
    qp.query_plan AS Query_Plan
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) qp
WHERE r.session_id > 50  -- 排除系统会话
AND r.status = 'running';

三、图形化工具(推荐)

1. SSMS 中的执行计划

  • 预估执行计划: Ctrl + L
  • 实际执行计划: Ctrl + M(然后执行查询)
  • 实时查询统计: 菜单 → 查询 → 实时查询统计

2. 查看执行计划的方式

sql 复制代码
-- 方法1:在查询前开启实际执行计划
SET STATISTICS XML ON;
GO
-- 你的查询
SELECT * FROM Ware_WareHouseBill WHERE WareHouseBillCode = '3161-5';
GO
SET STATISTICS XML OFF;

-- 方法2:保存执行计划到变量
DECLARE @plan_handle VARBINARY(64);
SELECT @plan_handle = plan_handle 
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
WHERE st.text LIKE '%Ware_WareHouseBill%';

SELECT * FROM sys.dm_exec_query_plan(@plan_handle);

四、针对你的问题的诊断脚本

sql 复制代码
-- 完整诊断你的查询
SET STATISTICS TIME ON;
SET STATISTICS IO ON;

-- 1. 检查主表数据
PRINT '=== 主表数据检查 ===';
SELECT WareHouseBillCode, Status, WareHouseBillType
FROM Ware_WareHouseBill 
WHERE WareHouseBillCode = '3161-5';

-- 2. 检查明细表数据
PRINT '=== 明细表数据检查 ===';
SELECT 
    l.WareHouseBillList_Id,
    l.CheckStatus,
    l.Status,
    l.ProductCode,
    l.LotCode
FROM Ware_WareHouseBill a
INNER JOIN Ware_WareHouseBillList l ON a.WareHouseBill_Id = l.WareHouseBill_Id
WHERE a.WareHouseBillCode = '3161-5';

-- 3. 查看执行计划(实际)
PRINT '=== 实际执行计划 ===';
SET STATISTICS XML ON;
SELECT * FROM
(
    SELECT
        a.WareHouseBill_Id, 
        a.WareHouseBillCode,
        a.Status,
        a.WareHouseBillType,
        c.SGName,
        (
            SELECT COUNT(WareHouseBillList_Id) 
            FROM Ware_WareHouseBillList l 
            WHERE l.WareHouseBill_Id = a.WareHouseBill_Id 
                AND (l.CheckStatus = 2 OR l.CheckStatus = 0 OR l.CheckStatus IS NULL) 
                AND l.Status != 3 
        ) AS uCoun
    FROM Ware_WareHouseBill AS a
        LEFT JOIN Base_Supplier AS c ON a.SUPPLIER_NO = c.SGCode 
    WHERE a.WareHouseBillCode = '3161-5'
) AS subquery;
SET STATISTICS XML OFF;

SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

五、关键指标解读

STATISTICS IO 输出解读:

  • 逻辑读取: 从缓存读取的页数(越少越好)
  • 物理读取: 从磁盘读取的页数(应为0或很小)
  • 扫描计数: 表扫描次数

STATISTICS TIME 输出解读:

  • CPU 时间: CPU 处理时间
  • 占用时间: 总执行时间

六、快速优化建议

针对你的查询,建议先运行以下诊断:

sql 复制代码
-- 快速诊断索引建议
SET STATISTICS TIME ON;
SET STATISTICS IO ON;

-- 测试查询性能
SELECT 
    a.WareHouseBillCode,
    COUNT(*) AS DetailCount,
    COUNT(CASE WHEN (l.CheckStatus IN (0,2) OR l.CheckStatus IS NULL) AND l.Status != 3 THEN 1 END) AS ValidCount
FROM Ware_WareHouseBill a
LEFT JOIN Ware_WareHouseBillList l ON a.WareHouseBill_Id = l.WareHouseBill_Id
WHERE a.WareHouseBillCode = '3161-5'
GROUP BY a.WareHouseBillCode;

SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

-- 查看缺失索引
SELECT * FROM sys.dm_db_missing_index_details 
WHERE OBJECT_NAME(object_id) IN ('Ware_WareHouseBill', 'Ware_WareHouseBillList');
相关推荐
IAtlantiscsdn2 小时前
Redis面试题总结
数据库·redis·缓存
尤老师FPGA2 小时前
petalinux制作linux系统flash+sd卡启动
linux·运维·服务器
桌面运维家2 小时前
Prometheus服务器监控告警实战指南
运维·服务器·prometheus
2501_924952692 小时前
自动化机器学习(AutoML)库TPOT使用指南
jvm·数据库·python
cyforkk3 小时前
前端架构实战:当服务器关闭时,如何优雅提示 502 错误?
服务器·前端·架构
诗酒当趁年华3 小时前
langchain核心组件1-智能体
数据库·langchain
流星白龙3 小时前
【MySQL】9.MySQL内置函数
android·数据库·mysql
原来是猿3 小时前
MySQL 在 Centos 7环境安装
数据库·mysql·centos
路小雨~3 小时前
Milvus 向量数据库的官方文档笔记
数据库·学习·milvus