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

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

相关推荐
零炻大礼包37 分钟前
【SQL server】数据库远程连接配置
数据库
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
令狐少侠20111 小时前
explain执行计划分析 ref_
mysql
随心............1 小时前
python操作MySQL以及SQL综合案例
数据库·mysql
€☞扫地僧☜€1 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
CopyDragon1 小时前
设置域名跨越访问
数据库·sqlite
xjjeffery1 小时前
MySQL 基础
数据库·mysql
写bug的小屁孩1 小时前
前后端交互接口(三)
运维·服务器·数据库·windows·用户界面·qt6.3
恒辉信达1 小时前
hhdb数据库介绍(8-4)
服务器·数据库·mysql
齐 飞2 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb