mysql 性能优化之Explain讲解

EXPLAIN是 MySQL 中用于分析查询执行计划的重要工具,通过它可以查看查询如何使用索引、扫描数据的方式以及表连接顺序等信息,从而找出性能瓶颈。以下是关于EXPLAIN的详细介绍和实战指南:

1. EXPLAIN 基本用法

SELECTINSERTUPDATEDELETE语句前加上EXPLAIN关键字即可查看执行计划:

EXPLAIN SELECT * FROM users WHERE age > 18;

2. 关键字段解析

EXPLAIN返回的结果包含多个字段,重点关注以下几个:

id
  • 查询的标识符,数值越大优先级越高,相同数值按顺序执行。
type
  • 数据访问类型,从最优到最差排序:
    • system/const:单条记录查询(主键或唯一索引)。
    • eq_ref:唯一索引扫描(如JOIN操作)。
    • ref:非唯一索引扫描。
    • range:范围扫描(如WHERE age > 18)。
    • index:全索引扫描(仅扫描索引树)。
    • ALL:全表扫描(性能最差)。
possible_keys
  • 可能使用的索引,但不一定实际使用。
key
  • 实际使用的索引,若为NULL则未使用索引。
key_len
  • 索引使用的字节数,用于评估索引的选择性。
rows
  • MySQL 估算的扫描行数,值越小越好。
Extra
  • 额外信息,常见值:
    • Using filesort:需额外排序(性能开销大)。
    • Using temporary:使用临时表(如GROUP BYORDER BY)。
    • Using index:覆盖索引(仅通过索引即可获取所有数据)。

3. 实战优化案例

案例 1:全表扫描优化

问题 SQL

SELECT * FROM orders WHERE status = 'paid';

EXPLAIN 结果

+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| 1  | SIMPLE      | orders | ALL  | NULL          | NULL | NULL    | NULL | 100000 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+

分析type=ALL(全表扫描),key=NULL(未使用索引)。
优化

ALTER TABLE orders ADD INDEX idx_status (status);

优化后 EXPLAIN

+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+
| 1  | SIMPLE      | orders | ref  | idx_status    | idx_status | 152     | const | 500  | Using index |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+

结果type=ref(索引扫描),rows=500(扫描行数大幅减少),Using index(覆盖索引)。

案例 2:复合索引优化

问题 SQL

SELECT user_id, amount FROM orders WHERE user_id = 100 AND status = 'paid';

EXPLAIN 结果

+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+
| 1  | SIMPLE      | orders | ref  | idx_user      | idx_user | 4       | const | 1000 | Using where |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------------+

分析:仅使用了user_id索引,未使用status条件。
优化:创建复合索引:

ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);

优化后 EXPLAIN

+----+-------------+--------+------+-------------------+-------------------+---------+-------------+------+-------------+
| id | select_type | table  | type | possible_keys     | key               | key_len | ref         | rows | Extra       |
+----+-------------+--------+------+-------------------+-------------------+---------+-------------+------+-------------+
| 1  | SIMPLE      | orders | ref  | idx_user_status   | idx_user_status   | 156     | const,const | 50   | Using index |
+----+-------------+--------+------+-------------------+-------------------+---------+-------------+------+-------------+

结果rows=50(扫描行数进一步减少),Using index(覆盖索引)。

案例 3:消除Using filesort

问题 SQL

SELECT * FROM products ORDER BY create_time LIMIT 10;

EXPLAIN 结果

+----+-------------+----------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows   | Extra          |
+----+-------------+----------+------+---------------+------+---------+------+--------+----------------+
| 1  | SIMPLE      | products | ALL  | NULL          | NULL | NULL    | NULL | 100000 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+--------+----------------+

分析:全表扫描后进行文件排序(Using filesort)。
优化:添加索引:

ALTER TABLE products ADD INDEX idx_create_time (create_time);

优化后 EXPLAIN

+----+-------------+----------+------+---------------+-------------------+---------+------+------+-------------+
| id | select_type | table    | type | possible_keys | key               | key_len | ref  | rows | Extra       |
+----+-------------+----------+------+---------------+-------------------+---------+------+------+-------------+
| 1  | SIMPLE      | products | index| NULL          | idx_create_time   | 5       | NULL | 10   | Using index |
+----+-------------+----------+------+---------------+-------------------+---------+------+------+-------------+

结果type=index(索引扫描),消除了Using filesort

4. 高级用法:EXPLAIN ANALYZE

MySQL 8.0+ 支持EXPLAIN ANALYZE,返回更详细的执行信息,包括实际扫描行数和时间:

EXPLAIN ANALYZE SELECT * FROM users WHERE age > 18;

5. 优化建议

  1. 优先优化type字段:尽量避免ALLindex类型,目标是ref或更优。
  2. 确保key字段非NULL:通过创建索引让查询使用索引。
  3. 消除Using filesortUsing temporary:通过合理索引避免额外排序和临时表。
  4. 利用覆盖索引:让Extra字段出现Using index,减少回表操作。
  5. 复合索引顺序:将选择性高的字段放在前面(如唯一值多的字段)。

6. 常见误区

  • 索引越多越好:过多索引会增加写操作开销和内存占用。
  • 忽视复合索引顺序:不满足最左匹配原则会导致索引失效。
  • 过度依赖EXPLAIN估算rows是估算值,实际可能有偏差,需结合SHOW PROFILE等工具验证。

通过EXPLAIN深入分析查询执行计划,针对性地优化索引和查询语句,可以显著提升 MySQL 性能。

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

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

相关文章

Redis 连接:深度解析与最佳实践

Redis 连接:深度解析与最佳实践 引言 Redis 作为一款高性能的内存数据结构存储系统,在当今的互联网应用中扮演着越来越重要的角色。高效的 Redis 连接管理对于保证系统的稳定性和性能至关重要。本文将深入探讨 Redis 连接的原理、配置以及最佳实践,帮助读者更好地理解和应…

C语言---VSCODE的C语言环境搭建

文章目录资源下载配置环境验证资源下载 站内下载 配置环境 解压压缩包,复制以下文件的路径 打开主页搜索系统环境变量 点击环境变量 选择系统变量中的Path,点击编辑 在最后面添加路径。 添加完成记得关机重启。 验证 重启电脑之后打开在Power…

ojdbc对应jdk版本附下载地址(截止20250722)

可以从Oracle官网查看, JDBC and UCP Downloads page

Redis为什么被设计成是单线程的?

Redis单线程模型解析 当我们说Redis是单线程时,特指"其网络IO和键值对读写操作由单个线程完成"。实际上,Redis仅网络请求模块和数据操作模块采用单线程设计,而持久化存储、集群支持等其他模块都采用了多线程架构。 事实上,Redis从4.0版本就开始对部分命令实现了…

基础流程图

一、常用符号及定义二、 画图基础规则1、从上至下,从左至右流向顺序。2、开始符号只能有一个出口。3、进程符号不做校验逻辑。4、相同流程图,符号大小应为一致。5、引用流程,不重复绘制。6、路径符号尽量避免交叉重叠。7、同一路径&#xff0…

C# 结构体

目录 1.如何定义一个结构体(struct 关键字) 2.如何使用一个结构体 3.如何修改一个数据 4.如何让去访问一个学生的信息 5、结构体数组 练习 1.如何定义一个结构体(struct 关键字) C#中public 、private、protect的区别 结构…

在Python中操作Word

生成请假条1.准备一个文件“template.docx”,内容如下。2.安装docxtpl库。pip install docxtpl3.执行代码,替换字典内容。from docxtpl import DocxTemplate# 读取定义模板文件 tpl DocxTemplate(template.docx) # 创建子文档 sd tpl.new_subdoc() # 添…

网络协议(四)网络层 路由协议

在网络层及网络层之上使用IP地址,IP地址放在IP数据报的首部,而MAC地址放在MAC帧的首部。通过数据封装,把IP数据报分组封装为MAC帧。 由于路由器的隔离,IP网络中无法通过广播MAC地址来完成跨网络的寻址,因此在网络层中只…

(后者可以节约内存/GPU显存)Pytorch中求逆torch.inverse和解线性方程组torch.linalg.solve有什么关系

假设我们要求A的逆矩阵,正常情况下我们使用如下命令: torch.inverse(A)但是本人发现,这个函数还挺消耗显存的。想到求逆矩阵和求线性方程组有很大关系。从而可以使用torch.linalg.solve来求解逆矩阵,关键是其显存消耗小。 求解逆矩…

esp32 idf 使用http访问json直接拼接content_length = -1

CMakeLists.txt添加网络请求库 REQUIRES esp_http_client效果图D (14235) HTTP_CLIENT: content_length -1 需要直接拼接content_length才能打印#include <stdio.h> #include <string.h> #include "esp_log.h" #include "esp_system.h" #inc…

[Github】下载使用github上的源代码

一、安装Anoconda 二、安装 Git &#xff08;1&#xff09;安装 方法 1&#xff1a;通过 Git 官网安装​ 下载 Git for Windows&#xff1a;https://git-scm.com/download/win运行安装程序&#xff0c;​​确保勾选 "Add Git to PATH"​​&#xff08;重要&#…

Java 邂逅 WebSocket:解锁实时通信的无限可能​

在当今的互联网时代&#xff0c;实时通信已经成为许多应用不可或缺的功能。从在线聊天工具到实时游戏互动&#xff0c;从股票行情推送再到物联网数据传输&#xff0c;都对实时性有着极高的要求。而在 Java 技术栈中&#xff0c;WebSocket 技术的出现&#xff0c;为开发者打开了…

MySQL 核心知识点梳理(5)

目录 事务 MySQL事务的四大特性 ACID 原子性 持久性 隔离性 事务的隔离级别 读未提交 读已提交 可重复读 串行化 事务的隔离级别如何实现 MVCC 版本链 READVIEW 高可用 MySQL数据库的读写分离 主从复制 主从同步延迟怎么处理 分库策略 水平分库分表的策略…

借助AI学习开源代码git0.7之六write-tree

借助AI学习开源代码git0.7之六write-tree write-tree.c 的作用是根据当前的索引&#xff08;cache&#xff09;内容创建一个树&#xff08;tree&#xff09;对象&#xff0c;并将其写入Git的对象数据库。 树对象代表了项目在某个时间点的目录结构。 代码的主要逻辑&#xff1a;…

开源 python 应用 开发(八)图片比对

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

SeaTunnel 云仓连接器使用指南 | AI 助手解读系列

最近体验了一下 Deepwiki 的 AI 文档生成功能&#xff0c;本文展示其自动生成的《SeaTunnel 云端数据仓库连接器》文档内容&#xff0c;欢迎大家一起“挑刺捉虫”&#xff0c;看看 AI 写技术文档到底靠不靠谱&#xff1f; 本文档介绍了 Apache SeaTunnel 的云数据仓库连接器&a…

每日算法刷题Day51:7.21:leetcode 栈6道题,用时1h40min

二.进阶 1.套路 2.题目描述 1.给你一个字符串 s 。它可能包含任意数量的 * 字符。你的任务是删除所有的 * 字符。 当字符串还存在至少一个 * 字符时&#xff0c;你可以执行以下操作&#xff1a; 删除最左边的 * 字符&#xff0c;同时删除该星号字符左边一个字典序 最小的字…

网络基础DAY16-MSTP-VRRP

STP/RSTP的局限性1.所有VLAN共享一棵生成树 2.无法实现不同VLAN在多条Trunk链路上的负载分担 3.次优化二层路径。MSTP的基本概念及优势MSTP的定义MST域拥有相同MST配置标识的网桥构成的集合。 具体如何分辨是否是同一个域&#xff0c;就看域名&#xff0c;配置修订号&#xff0…

freertos关键函数理解 uxListRemove

//删除pxItemToRemove节点 UBaseType_t uxListRemove(ListItem_t *pxItemToRemove) { //The list item knows which list it is in. Obtain the list from the list item.//找到节点所在的链表//my_printf( "uxListRemove pxItemToRemove %#p\n", pxI…

C语言---番外篇(柔性数组)

前言&#xff1a; 由于这块内容所谓综合性比较高&#xff0c;有数组的知识&#xff0c;有结构体的知识&#xff0c;还有动态内存管理的知识&#xff0c;所以我就单独写一篇博客&#xff0c;此谓番外篇。 柔性数组的概念 定义在结构体的最后一个元素的位置且大小未知的数组就叫…