讲解

EXPLAIN 让优化器「说出」它打算怎么执行你的查询,是分析慢查询的第一工具。输出里最该关注的列:type 是访问类型,从好到差大致是 const > eq_ref > ref > range > index > ALL,出现 ALL(全表扫描)且表很大就要警惕;key 是实际使用的索引,NULL 表示没用索引;rows 是优化器估算要扫描的行数;filtered 是条件过滤后剩余比例;Extra 是附加信息,Using index 是好信号(覆盖索引),Using filesort 和 Using temporary 则提示排序、分组没能利用索引。

多表连接时 EXPLAIN 输出多行,第一行是先访问的「驱动表」。优化器通常选过滤后行数少的表当驱动表,连接列有索引的被驱动表会显示 eq_ref 或 ref——两表连接里看到被驱动表是 ALL,基本就是连接列缺索引。

EXPLAIN ANALYZE 是 8.0.18 起的大招:它真的执行查询,并报告每个节点的实际耗时和实际行数,和估算值对比能立刻发现「优化器估错了行数」这类问题。注意它会真的执行——对 SELECT 用没问题,千万别对 UPDATE/DELETE 顺手加一个。需要机器可读格式时用 EXPLAIN FORMAT=JSON,里面包含成本(cost)明细。

示例

重建用户表并造一万行,再加一张两千行的订单表(user_id 上有索引):

CREATE TABLE users (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  city VARCHAR(20) NOT NULL,
  age INT NOT NULL
);

CREATE TABLE orders (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  user_id INT UNSIGNED NOT NULL,
  amount DECIMAL(10,2) NOT NULL,
  KEY idx_user_id (user_id)
);

SET SESSION cte_max_recursion_depth = 100000;

INSERT INTO users (name, city, age)
WITH RECURSIVE seq AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM seq WHERE n < 10000
)
SELECT CONCAT('user', n), ELT(1 + n MOD 5, '北京', '上海', '广州', '深圳', '杭州'), 18 + n MOD 40
FROM seq;

INSERT INTO orders (user_id, amount)
WITH RECURSIVE seq AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM seq WHERE n < 2000
)
SELECT 1 + n MOD 10000, 10 + n MOD 90 FROM seq;

读一个两表连接的计划:驱动表 orders 因 amount 无索引是 range/ALL,被驱动表 users 走主键 eq_ref——这就是「连接列有索引」的健康形态:

EXPLAIN SELECT u.name, o.amount
FROM orders AS o JOIN users AS u ON u.id = o.user_id
WHERE o.amount > 80\G

EXPLAIN ANALYZE 实际执行并给出真实耗时与行数,对比估算值可以看出优化器靠不靠谱:

EXPLAIN ANALYZE SELECT city, COUNT(*) AS cnt FROM users GROUP BY city ORDER BY cnt DESC LIMIT 3\G

常见坑

  • 把 rows 当精确值:rows 是基于统计信息的估算,可能和实际差一个数量级。统计信息过时执行计划就会选错,ANALYZE TABLE 可以刷新。
  • 见 ALL 就慌:小表全表扫描比走索引还快,type=ALL 只有在大表上才是问题。判断慢不慢要结合表的实际规模。
  • 以为 Using filesort 是写磁盘:filesort 只是「额外排序」的意思,多数在内存完成。它提示排序没用上索引,是否需要优化要看数据量。
  • 对写操作用 EXPLAIN ANALYZE:它会真执行。8.0 支持 EXPLAIN ANALYZE 用于 SELECT,也可以用于 INSERT/UPDATE/DELETE——别在生产上试后者。

小结

EXPLAIN 重点看 type(别出 ALL)、key(用上索引)、rows(估算行数)、Extra(Using index 好、filesort/temporary 留意);EXPLAIN ANALYZE 给出真实执行数据。下一章进入另一个核心机制:事务与锁。