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';

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

相关推荐
m0_7482448318 分钟前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝28 分钟前
Redis 介绍和安装
数据库·redis·缓存
wmd1316430671243 分钟前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!1 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱1 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence1 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236581 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库
苏三说技术1 小时前
Redis 性能优化的18招
数据库·redis·性能优化
Tttian6222 小时前
基于Pycharm与数据库的新闻管理系统(2)Redis
数据库·redis·pycharm
做梦敲代码2 小时前
达梦数据库-读写分离集群部署
数据库·达梦数据库