用EXPLAIN洞察SQL执行计划:从"盲目编写"到"精准优化"

很多开发者在编写SQL时仅凭直觉,直到查询超时才发现问题。MySQL内置的EXPLAIN工具能提前揭示查询执行逻辑,帮助预防性能隐患。本文将带你掌握EXPLAIN的核心用法,让SQL优化从经验导向转变为数据驱动。

一、EXPLAIN:揭秘SQL查询的执行过程

EXPLAIN是MySQL强大的查询分析工具,通过在SQL语句前添加该关键字即可获取详细的执行计划,包括:

  • 表的访问顺序
  • 索引使用情况
  • 预估扫描行数
  • 是否存在全表扫描、临时表或文件排序等性能瓶颈

使用示例

-- 基础查询分析
EXPLAIN SELECT id, name FROM products WHERE category='自行车';-- 深度分析复杂查询
EXPLAIN FORMAT=JSON SELECT * FROM orders JOIN customers ON orders.cust_id=customers.id;

执行结果包含10余个关键字段,其中4个核心指标是性能优化的重点依据。

二、四大核心指标:快速定位查询瓶颈

核心指标优化指南

指标功能说明性能参考值优化重点检测方法
type表访问方式最优:const/eq_ref
良好:ref/range
需优化:index/ALL
避免ALL(全表扫描),争取达到range及以上检查执行计划中的type
rows预估扫描行数优秀:<100
良好:100-1000
需优化:≥1000
通过索引优化减少扫描行数对比rows与实际返回行数
key实际使用索引理想:非NULL
需优化:NULL
确保查询条件、连接和排序字段使用索引验证key是否为预期索引
Extra附加信息良好:Using index
需优化:filesort/Using temporary
消除文件排序和临时表关注负面提示信息

1. type:访问方式(关键性能指标)

type反映表的访问方式,性能从优到劣排序:

类型说明性能优化建议
ALL全表扫描最差必须创建索引
index索引全扫描较差优化查询范围
range索引范围扫描中等合理,可优化范围
ref非唯一索引匹配良好推荐,保持索引高选择性
eq_ref唯一索引匹配优秀理想状态
const常量查询最优最佳性能

关键提示:发现type=ALL(全表扫描)需立即优化。

2. rows:预估扫描行数

rows表示优化器预估的扫描行数,数值与性能成反比:

  • 全表扫描时接近表总行数
  • 高效查询应远小于总行数

优化建议

  • rows远大于实际返回行数时,执行ANALYZE TABLE 表名更新统计信息
  • 通过索引优化将rows控制在1000以内(大数据表需更严格)

3. key:实际使用索引

key显示查询实际使用的索引,NULL表示未使用索引(通常伴随type=ALL

常见索引失效原因

  • 索引字段被函数处理(如DATE(create_time)
  • 违反联合索引最左前缀原则
  • 数据量过小,优化器选择全表扫描

4. Extra:执行细节

Extra包含关键执行信息,需重点关注:

信息说明影响优化建议
Using index覆盖索引正面无需优化
filesort文件排序负面使用索引排序
Using temporary临时表负面优化GROUP BY/ORDER BY
Using where回表查询中性扩展为覆盖索引

三、实战案例:用EXPLAIN诊断与优化

案例1:全表扫描优化(type=ALL)

项目优化前优化后
SQLSELECT * FROM products WHERE category='自行车'同左,添加idx_category索引
typeALLref
keyNULLidx_category
rows1000005000
ExtraUsing whereUsing index(若只查索引字段)
执行时间1.2s0.06s

优化步骤

  1. 创建索引:CREATE INDEX idx_category ON products(category);
  2. 原理:通过索引快速定位category='自行车'的记录,避免全表扫描。

案例2:filesort优化(Extra=filesort)

项目优化前优化后
SQLSELECT * FROM orders WHERE user_id=100 ORDER BY create_time同左,添加idx_user_create联合索引
typerefref
keyidx_user_ididx_user_create
rows5050
ExtrafilesortUsing index
执行时间0.8s0.05s

优化步骤

  1. 创建联合索引:CREATE INDEX idx_user_create ON orders(user_id, create_time);
  2. 原理:联合索引包含筛选(user_id)和排序(create_time)字段,利用索引有序性避免filesort。

案例3:索引失效场景汇总

场景A:函数处理索引字段

错误示例

EXPLAIN SELECT * FROM orders WHERE DATE(create_time)='2023-01-01';
-- 执行计划:type=ALL,key=NULL(索引失效)

优化方案

EXPLAIN SELECT * FROM orders 
WHERE create_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59';
-- 执行计划:type=range,key=idx_create_time(索引生效)
场景B:使用NOT/!=/<>操作符

错误示例

EXPLAIN SELECT * FROM products WHERE price != 100;
-- 执行计划:type=ALL,key=NULL(索引失效)

优化方案

-- 拆分范围查询(适用于数值型字段)
EXPLAIN SELECT * FROM products WHERE price < 100 
UNION ALL 
SELECT * FROM products WHERE price > 100;
-- 执行计划:type=range,key=idx_price(索引生效)
场景C:OR连接条件(部分字段无索引)

错误示例

EXPLAIN SELECT * FROM users WHERE mobile='13800138000' OR email='test@example.com';
-- 执行计划:type=ALL,key=NULL(仅mobile有索引,email无索引)

优化方案

-- 改为UNION ALL(需两个字段均有索引)
EXPLAIN SELECT * FROM users WHERE mobile='13800138000'
UNION ALL
SELECT * FROM users WHERE email='test@example.com';
-- 执行计划:type=ref,key=idx_mobile/idx_email(双索引生效)
场景D:隐式类型转换

错误示例

EXPLAIN SELECT * FROM users WHERE mobile=13800138000;
-- 执行计划:type=ALL,key=NULL(mobile为字符串类型,查询用数字)

优化方案

EXPLAIN SELECT * FROM users WHERE mobile='13800138000';
-- 执行计划:type=ref,key=idx_mobile(类型匹配,索引生效)

案例4:复合问题优化(全表扫描+filesort)

原始查询

EXPLAIN SELECT * FROM products 
WHERE price>100 AND category='自行车' 
ORDER BY create_time;
-- 执行计划:type=ALL,key=NULL,Extra=Using where; filesort(双问题)

优化步骤

  1. 创建联合索引:CREATE INDEX idx_cat_price_time ON products(category, price, create_time);
  2. 优化后执行计划:
    • type=rangekey=idx_cat_price_timeExtra=Using index
    • 扫描行数从50000→800,执行时间从2.1s→0.09s

案例5:大数据量表分页优化(百万级数据)

原始查询

EXPLAIN SELECT * FROM orders 
WHERE user_id=1000 AND status='paid'
ORDER BY create_time DESC 
LIMIT 20 OFFSET 100;
-- 执行计划:type=ref,key=idx_user_id,Extra=filesort(偏移+排序双问题)

优化方案

  1. 创建联合索引:CREATE INDEX idx_user_status_time ON orders(user_id, status, create_time);
  2. 优化后执行计划:
    • type=refkey=idx_user_status_timeExtra=Using index
    • 执行时间从1.5s→0.07s

四、高效索引创建指南

1. 索引选择性:判断索引是否高效

选择性:字段不重复值数 / 总记录数(值越接近1,索引越高效)。

行业案例

  • 电商用户表:
    • user_id:选择性=1.0(唯一标识,必建索引)
    • gender:选择性=0.5(仅男/女,不建议建索引)
  • 物流订单表:
    • order_no:选择性=1.0(唯一单号,必建索引)
    • status:选择性=0.2(5种状态,仅在筛选特定状态时建索引)

计算示例

-- 低选择性字段(状态)
SELECT COUNT(DISTINCT status)/COUNT(*) FROM orders;  -- 结果≈0.2-- 高选择性字段(订单号)
SELECT COUNT(DISTINCT order_no)/COUNT(*) FROM orders;  -- 结果≈1.0

注意:索引选择性计算需要定期更新(ANALYZE TABLE),否则可能因统计信息过期导致误判。

2. 索引类型与创建规范

单字段索引

为筛选、JOIN、排序字段创建:

-- 筛选字段索引
CREATE INDEX idx_customer_id ON customers(cust_id);-- 长字符串前缀索引(节省空间)
CREATE INDEX idx_product_name ON products(name(20));  -- 取前20字符
联合索引(最左前缀原则)

联合索引(a,b,c)仅在查询包含最左字段时生效:

有效查询无效查询
WHERE a=1WHERE b=2(缺最左a)
WHERE a=1 AND b=2WHERE a=1 AND c=3(跳过b)
WHERE a=1 ORDER BY bWHERE b=2 ORDER BY c(缺a)

创建语法

-- 筛选+排序联合索引(先筛选,后排序)
CREATE INDEX idx_user_status_time ON orders(user_id, status, create_time);

3. 索引数量建议(平衡读写性能)

表类型读/写比建议索引数量
读密集表>100:15-10个
均衡表10:1≤5个
写密集表(如日志、订单)<10:1≤3个

警示:在超过500万行的表上创建索引需要评估锁表时间,建议在业务低峰期执行。

五、查询性能优化五步法

  1. 编写基础查询:优先确保业务逻辑正确性,获得准确结果集;
  2. 分析执行计划:使用EXPLAINEXPLAIN FORMAT=JSON获取查询路径;
  3. 定位性能瓶颈
    • 检查type字段是否出现ALL/index等低效扫描;
    • 关注rows预估行数是否异常偏高;
    • 排查Extra字段是否包含filesort/temporary等警告;
    • 验证key字段是否实际使用了目标索引;
  4. 实施优化方案
    • 索引优化:增删索引、调整联合索引字段顺序;
    • SQL重构:避免索引字段函数计算、用UNION替换OR条件、改进分页查询;
  5. 验证优化效果:对比优化前后执行计划的typerowsExtra关键指标变化。

六、索引使用五大误区

  1. 索引滥用:盲目增加索引数量,显著降低数据写入效率;
  2. 顺序错配:联合索引中将低区分度字段前置,严重削弱索引效果;
  3. 长度不足:过短的前缀索引导致过滤效率低下;
  4. 环境混淆:测试环境机械复制生产索引配置,忽略数据规模差异;
  5. 维护缺失:长期未更新统计信息,造成优化器决策偏差。

核心总结

EXPLAIN作为SQL性能分析的利器,通过typerowskeyExtra四大核心维度精准定位问题。优化本质在于:基于业务特征设计精准索引,严格遵守最左前缀原则,规避常见失效场景。切记,最优索引策略是平衡的艺术——在查询性能和写入开销间取得完美平衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94912.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94912.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/94912.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电影艺术好,电影知识得学

关于电影应该谈什么导演风格、演员技术、剧本结构、票房、政治因素等。一、纸上谈电影电影制作期&#xff1a;研发、前制、拍摄、后制、发行。一般成员只在某个时期出现。制片和导演会从头监督到尾。研发期&#xff1a; 剧本概念发想与成形的时期。创作自由度比较大&#xff0c…

FPGA学习笔记——简易的DDS信号发生器

目录 一、任务 二、分析 三、ROM IP核配置 四、Visio图 五、代码 &#xff08;1&#xff09;.v代码 &#xff08;2&#xff09;仿真代码 六、仿真 七、实验现象 一、任务 用串口模块&#xff0c;用上位机发送指令&#xff0c;FPGA接收&#xff0c;然后输出对应的波形&…

在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏 (中)

接上篇 在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏&#xff08;上&#xff09; 通过上篇的分析&#xff0c;发现问题在采集数据到传入GPU之前的阶段。但随着新一轮长时间测试发现&#xff0c;问题依然存在。 如上图&#xff0c;在运行20多分钟内存开始…

计数组合学7.17(Murnaghan–Nakayama 规则 )

7.17 Murnaghan–Nakayama 规则 我们已经成功地用基 mλm_\lambdamλ​、hλh_\lambdahλ​ 和 eλe_\lambdaeλ​ 表示了 Schur 函数 sλs_\lambdasλ​。本节我们将考虑幂和对称函数 pλp_\lambdapλ​。一个斜分划 λ/μ\lambda / \muλ/μ 是连通的&#xff0c;如果其分拆图…

使用 jlink 构建轻巧的自定义JRE

从 JDK 9 开始&#xff0c;Oracle JDK 和 OpenJDK 不再默认包含独立的 JRE 目录&#xff0c;而是提供了 jlink 工具&#xff08;Java 链接器&#xff09;&#xff0c;允许你根据需求自定义生成最小化的 JRE&#xff08;包含必要的模块&#xff09;。以下是使用 jlink 生成 JRE …

[IOMMU]面向芯片/SoC验证工程的IOMMU全景速览

面向芯片/SoC验证工程的IOMMU全景速览 摘要:面向芯片/SoC 验证工程的 IOMMU 全景速览:包含基础概念、主流架构要点(ARM SMMU、Intel VT‑d、RISC‑V IOMMU),Linux 软件栈关系,SoC 上的验证方法(功能、错误、性能、系统化流程和覆盖),以及一个可用的“通用 IOMM…

Jenkins全链路教程——Jenkins用户权限矩阵配置

在企业级CI/CD场景中&#xff0c;“权限混乱”往往比“构建失败”更致命——测试员误删生产流水线、实习生修改关键插件配置、多团队共用账号导致责任无法追溯……这些问题&#xff0c;99%都能用权限矩阵彻底解决&#xff01;今天&#xff0c;我们不仅会拆解权限矩阵的底层逻辑…

库函数蜂鸣器的使用(STC8)

使用库函数控制蜂鸣器&#xff08;STC8&#xff09; 在STC8系列单片机中&#xff0c;可以通过库函数或直接操作寄存器来控制蜂鸣器。以下是基于STC8库函数的常用方法&#xff1a; GPIO板蜂鸣器 #include "GPIO.h" #include "Delay.h"void GPIO_config()…

redis8.0.3部署于mac

macOS11因版本过低&#xff0c;安装redis时&#xff0c;Homebrew和源码编译两种方式都无法成功。将操作系统升级至macOS15再安装。Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库&#xff0c;遵守 BSD 协议&#xff0c;它提供了一个高性能的键值…

【和春笋一起学C++】(三十三)名称空间的其他特性

目录 嵌套式名称空间 拓展——未命名的名称空间 嵌套式名称空间 示例代码1&#xff1a; namespace electronicEquipment {namespace computer{double price 4999.0;string modelNumber;string name;}namespace ElectronicWatch{double price 99.0;string modelNumber;stri…

异步电动机负载运行特性全解析

异步电动机负载运行特性详解 ——从空载到负载的完整分析一、为什么需要再谈“负载运行” 在上一篇《感应电动机空载特性深度剖析》中&#xff0c;我们已经看到&#xff1a;空载时&#xff0c;若定子加额定电压&#xff0c;转子转速 $n \approx n_s$&#xff08;同步转速&#…

使用 Ansys Discovery 进行动态设计和分析

Ansys Discovery 是一款多功能工具&#xff0c;为创建模型、探索仿真设计和分析解决方案提供了一个单一的交互式工作区。它允许用户使用直接建模技术创建和修改几何结构&#xff0c;定义仿真并与结果实时交互。Discovery 支持结构、流体流动、热和电磁设计&#xff0c;提供直观…

力扣热题100-----118.杨辉三角

案例 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]] 提示: 1 …

NTP /Chrony 网络时间协议

一、NTP&#xff08;network time protocol&#xff09;网络时间协议&#xff1a;实现时间同步&#xff0c;让设备时间与国际标准时间保持一致设备日志、服务日志需要记录时间分布式系统&#xff08;分布式数据库、分布式缓存、分布式储存、消息队列&#xff09;时间戳&#xf…

VSCode 刷 LeetCode 算法题配置教程

LeetCode 在线刷题地址&#xff1a;https://leetcode-cn.com/ 一、安装 Node.js 环境 LeetCode 插件依赖 node.js 运行环境&#xff0c;因此必须先安装&#xff1a; 前往官网下载安装&#xff1a;https://nodejs.cn/download/下载好的压缩包解压&#xff0c;可以看到当前文件…

非常简单!从零学习如何免费制作一个lofi视频

想必大家在网上会看到如下类似的音乐频道&#xff0c;这类频道都只是上传简单的Lo-Fi音乐带着循环播放的背景就可以赚钱。 那么上面的效果如何实现的呢&#xff1f;今天做一个可以免费制作lo-Fi音乐的教程。 Lo-Fi音乐&#xff1a; Lo-Fi音乐是一种以低保真度和模拟音色为特点…

基于 RAUC 的 Jetson OTA 升级全攻略

&#x1f4d6; 推荐阅读&#xff1a;《Yocto项目实战教程:高效定制嵌入式Linux系统》 &#x1f3a5; 更多学习视频请关注 B 站&#xff1a;嵌入式Jerry 基于 RAUC 的 Jetson OTA 升级全攻略 0. 引子&#xff1a;常见问题 在 Jetson 平台做 OTA 升级时&#xff0c;你可能会问&…

MySQL 主备(Master-Slave)复制 的搭建

一、主备架构简介 Master&#xff08;主库&#xff09;&#xff1a;负责处理所有写操作&#xff08;INSERT/UPDATE/DELETE&#xff09;&#xff0c;并记录二进制日志&#xff08;binlog&#xff09;。Slave&#xff08;备库&#xff09;&#xff1a;从主库拉取 binlog&#xff…

【三个数绝对值排序】2022-10-10

缘由绝对值比较&#xff0c;总是跑不过怎么办-编程语言-CSDN问答 template <class 形参> inline void 算交换(形参& a, 形参& b){ 形参 ab a - b; a - ab; b ab; } template <class 形参> void 三个升序(形参& a, 形参& b, 形参& c) {if (a…

【LoRA模型训练】Stable Diffusion LoRA 模型秋叶训练器详细教程

一、工具简介与安装指南 1.1 秋叶 LoRA 训练器概述 秋叶 LoRA 训练器&#xff08;基于 Akegarasu/lora-scripts 项目&#xff09;是针对 Stable Diffusion 模型的轻量化微调工具&#xff0c;通过低秩适应&#xff08;LoRA&#xff09;技术实现高效参数微调。其核心优势在于&a…