MySQL中 EXPLAIN 的使用介绍

Day08-11. MySQL-索引-结构_哔哩哔哩_bilibili

使用 EXPLAIN

在查询语句前加上 EXPLAIN 关键字:

复制代码
EXPLAIN SELECT * FROM orders WHERE customer_id = 123 AND order_date > '2023-01-01';

执行上述 EXPLAIN 语句,查看输出结果。MySQL 会返回一个包含查询执行计划的表格(如下)。

具体解释:

EXPLAIN 输出表格包含多个列,每列提供不同的查询计划信息。常见列包括:

1、id:查询的标识符,表示查询的执行顺序。

2、select_type:查询类型,如 SIMPLE(简单查询),PRIMARY(主查询),UNION(联合查询的一部分),SUBQUERY(子查询)。

3、table:查询涉及的表。

4、type:连接类型,表示MySQL如何查找行。常见类型按效率从高到低排列为:

  • system:表只有一行(常见于系统表)。

  • const:表最多有一个匹配行(索引为主键或唯一索引)。

  • eq_ref:对于每个来自前一个表的行,表中最多有一个匹配行。

  • ref:对于每个来自前一个表的行,表中可能有多个匹配行。

  • range:使用索引查找给定范围的行。

  • index:全表扫描索引。

  • ALL:全表扫描。

5、possible_keys:查询中可能使用的索引。

6、key:实际使用的索引。

7、key_len:使用的索引键长度。

8、ref:使用的列或常量,与索引比较。

9、rows:MySQL 估计的要读取的行数。

10、filtered:经过表条件过滤后的行百分比。

11、Extra:额外的信息,如 Using index(覆盖索引),Using where(使用 WHERE 子句过滤),Using filesort(文件排序),Using temporary(使用临时表)。

优化查询路径

根据 EXPLAIN 输出,采取以下措施优化查询路径:

确保使用索引

如果 type 列显示为 ALL 或 index,说明表进行了全表扫描。可以通过创建适当的索引来优化查询。例如:

复制代码
CREATE INDEX idx_customer_date ON orders (customer_id, order_date);

优化查询条件

避免在索引列上使用函数或进行计算。改写查询条件以利用索引。例如:

复制代码
-- 避免SELECT * FROM orders WHERE YEAR(order_date) = 2023;

-- 改为SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';

使用覆盖索引

如果查询只涉及索引中的列,可以避免回表,提高性能。例如:

复制代码
CREATE INDEX idx_covering ON orders (customer_id, order_date, order_id);
-- 查询只涉及索引中的列SELECT customer_id, order_date, order_id FROM orders WHERE customer_id = 123;

分解复杂查询

将复杂查询分解为多个简单查询,可以提高性能。例如:

复制代码
-- 复杂查询SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.name = 'John Doe';
-- 分解为两个简单查询SELECT id FROM customers WHERE name = 'John Doe';-- 假设查询结果为 123SELECT * FROM orders WHERE customer_id = 123;

实际示例

假设有一个 employees 表和一个 departments 表:

复制代码
CREATE TABLE employees (    id INT AUTO_INCREMENT PRIMARY KEY,    first_name VARCHAR(50),    last_name VARCHAR(50),    department_id INT,    hire_date DATE,    INDEX (department_id),    INDEX (hire_date));
CREATE TABLE departments (    id INT AUTO_INCREMENT PRIMARY KEY,    name VARCHAR(50));

查询所有在某个日期后加入某部门的员工:

复制代码
EXPLAINSELECT e.id, e.first_name, e.last_nameFROM employees eJOIN departments d ON e.department_id = d.idWHERE d.name = 'Sales' AND e.hire_date > '2023-01-01';

示例 EXPLAIN 输出:

复制代码
+----+-------------+-------+--------+---------------+---------+---------+-------------------+------+--------------------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref               | rows | Extra                    |+----+-------------+-------+--------+---------------+---------+---------+-------------------+------+--------------------------+|  1 | SIMPLE      | d     | const  | PRIMARY       | PRIMARY | 4       | const             |    1 |                          ||  1 | SIMPLE      | e     | ref    | department_id | department_id | 4 | const             |   10 | Using where              |+----+-------------+-------+--------+---------------+---------+---------+-------------------+------+--------------------------+

从 EXPLAIN 输出可以看出:

  • d 表使用了 PRIMARY 索引,类型为 const,表示是一个常量查找。

  • e 表使用了 department_id 索引,类型为 ref,表示引用查找。

进一步优化:

  • 如果查询频繁,可以为 departments.name 创建索引。

  • 确保 hire_date 上有索引。

优化后的索引创建:

复制代码
CREATE INDEX idx_department_name ON departments (name);

再次执行 EXPLAIN:

复制代码
EXPLAINSELECT e.id, e.first_name, e.last_nameFROM employees eJOIN departments d ON e.department_id = d.idWHERE d.name = 'Sales' AND e.hire_date > '2023-01-01';

优化后的输出可能显示更好的执行计划,减少查询时间。

相关推荐
草巾冒小子几秒前
brew 安装mysql,启动,停止,重启
数据库·mysql
用户6279947182627 分钟前
南大通用GBase 8c分布式版本gha_ctl 命令-HI参数详解
数据库
斯汤雷15 分钟前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
SQLplusDB22 分钟前
Oracle 23ai Vector Search 系列之3 集成嵌入生成模型(Embedding Model)到数据库示例,以及常见错误
数据库·oracle·embedding
喝醉酒的小白43 分钟前
SQL Server 可用性组自动种子设定失败问题
数据库
chem41111 小时前
Conmon lisp Demo
服务器·数据库·lisp
m0_555762901 小时前
QT 动态布局实现(待完善)
服务器·数据库·qt
孪生质数-2 小时前
SQL server 2022和SSMS的使用案例1
网络·数据库·后端·科技·架构
振鹏Dong2 小时前
MySQL 事务底层和高可用原理
数据库·mysql
·云扬·2 小时前
深度剖析 MySQL 与 Redis 缓存一致性:理论、方案与实战
redis·mysql·缓存