从零开始搞懂 MySQL 的 explain:type 和 select_type 到底啥意思?

先从最朴素的查询开始

假设我们有个超级简单的表 users,里面存了用户信息:

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

INSERT INTO users (id, name, email) VALUES 
(1, 'Alice', 'alice@example.com'),
(2, 'Bob', 'bob@example.com'),
(3, 'Charlie', 'charlie@example.com');

现在我们跑个最简单的查询:

sql 复制代码
EXPLAIN SELECT * FROM users WHERE id = 1;

结果大概长这样:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE users const PRIMARY PRIMARY 4 const 1 Using index

别慌,咱们先搞懂 select_typetype 是啥。


select_type:查询的类型

select_type 告诉你这条查询在整个执行计划里是个什么角色。简单来说,它描述的是查询的"身份"。常见的值有:

  • SIMPLE :最简单的查询,没有子查询、没有 UNION。比如上面这个例子,就是 SIMPLE,因为它就是一个单表查询。
  • PRIMARY :如果是多表查询或者有子查询,最外层的那个查询会被标记为 PRIMARY
  • SUBQUERY :子查询,比如 WHERE id IN (SELECT id FROM another_table) 里的子查询。
  • UNION :多个查询用 UNION 合并时,第二个及之后的查询会被标记为 UNION

回到上面的例子,select_typeSIMPLE,因为这只是一个单表、无子查询的简单查找。后面我们会看到更复杂的例子。


type:访问方式

type 是重头戏,它告诉你 MySQL 是怎么从表里捞数据的,也就是访问方式。性能从高到低大概是这样排序的:const > eq_ref > ref > range > index > ALL。咱们一个一个讲,顺便配上例子。

1. const
  • 啥意思:MySQL 通过主键或者唯一索引直接定位到一行数据,效率贼高。
  • 例子 :上面的 WHERE id = 1,因为 id 是主键,MySQL 直接找到那行,结果就是 const
  • 形象记忆:就像你在家门口放了个信箱,地址写得清清楚楚,邮递员直接塞进去,不用翻遍整个小区。
2. eq_ref
  • 啥意思:通常在联表查询(JOIN)中,通过主键或唯一索引精确匹配一行。

  • 例子 : 假设还有个表 orders

    sql 复制代码
    CREATE TABLE orders (
        order_id INT PRIMARY KEY,
        user_id INT,
        FOREIGN KEY (user_id) REFERENCES users(id)
    );
    INSERT INTO orders (order_id, user_id) VALUES (101, 1), (102, 2);

    查询:

    sql 复制代码
    EXPLAIN SELECT u.name, o.order_id FROM users u JOIN orders o ON u.id = o.user_id;

    对于 orders 表,type 会是 eq_ref,因为 user_id 通过主键 id 一对一匹配。

  • 结果表

    id select_type table type possible_keys key rows Extra
    1 SIMPLE u ALL PRIMARY NULL 3
    1 SIMPLE o eq_ref user_id user_id 1
  • 形象记忆:就像你拿身份证去银行柜台办业务,柜员直接通过你的唯一号码查到你。

3. ref
  • 啥意思:通过非唯一索引查找,可能返回多行。

  • 例子 : 给 usersname 加个普通索引:

    sql 复制代码
    CREATE INDEX idx_name ON users(name);
    EXPLAIN SELECT * FROM users WHERE name = 'Alice';

    因为 name 不是唯一的,typeref

  • 结果表

    id select_type table type possible_keys key rows Extra
    1 SIMPLE users ref idx_name idx_name 1
  • 形象记忆:就像你在学校找叫"Alice"的同学,可能有好几个,得挨个问。

4. range
  • 啥意思 :通过索引做范围查找,比如 ><BETWEEN

  • 例子

    sql 复制代码
    EXPLAIN SELECT * FROM users WHERE id BETWEEN 1 AND 2;

    typerange,因为用主键查了个范围。

  • 结果表

    id select_type table type possible_keys key rows Extra
    1 SIMPLE users range PRIMARY PRIMARY 2 Using where
  • 形象记忆:就像你在超市找价格在 10 到 20 块之间的商品,得扫一眼货架。

5. index
  • 啥意思:扫描整个索引树,比全表扫描好点,但还是不够快。

  • 例子

    sql 复制代码
    EXPLAIN SELECT name FROM users;

    如果只查索引覆盖的字段,typeindex

  • 形象记忆:像翻电话簿,虽然有索引,但得从头翻到尾。

6. ALL
  • 啥意思:全表扫描,最慢的方式。

  • 例子

    sql 复制代码
    EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com';

    没索引,typeALL

  • 结果表

    id select_type table type possible_keys key rows Extra
    1 SIMPLE users ALL NULL NULL 3 Using where
  • 形象记忆:像大海捞针,一行一行找。


朴素策略的问题

从上面的例子看,最朴素的查询(比如 ALL)效率低得可怕。假设 users 表有 100 万行数据,全表扫描得扫 100 万次,时间成本和资源消耗都爆炸。更别提多表联查了,如果两个表都全扫描,复杂度直接平方级别上升。

不利因子:

  1. 没索引:MySQL 只能挨个儿看每行,像盲人摸象。
  2. 范围不明确 :即使有索引,如果条件太模糊(比如 email LIKE '%alice%'),还是得扫描大量数据。
  3. 联表效率低:没有合适的键关联,JOIN 操作会变成噩梦。

优化方向:逼近主流方案

基于这些问题,优化思路其实跟现在的数据库设计不谋而合:

  1. 加索引

    • 主键和唯一索引让 consteq_ref 成为可能。
    • 普通索引支持 refrange,大幅减少扫描行数。
    • 示例:给 email 加索引,typeALL 变成 ref
  2. 覆盖索引

    • 查询只涉及索引字段时,type 可以是 index,避免回表。
    • 示例:SELECT name FROM usersidx_name 覆盖。
  3. 优化联表

    • 用外键或索引确保 JOIN 用上 eq_refref
    • 示例:orders.user_id 加索引,JOIN 时效率飞升。
  4. 条件收窄

    • 用精确条件(=, IN)替代模糊匹配(LIKE '%...%'),让 range 更高效。

这些优化方向正是现代数据库的标配,比如 B+ 树索引、联合索引、主从架构,都是为了把扫描范围缩到最小,把 type 尽量往 consteq_ref 靠拢。


总结

select_type 是查询的身份标签,type 是捞数据的具体手法。咱们从最简单的 SIMPLEconst 开始,逐步看到 ALL 的低效,再通过索引和条件优化逼近高效方案。记住这些形象比喻,下次看 explain 就能秒懂啦!

相关推荐
Mahir088 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
IT_陈寒12 小时前
Redis缓存击穿把我整不会了,原来还有这手操作
前端·人工智能·后端
kyriewen13 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
文心快码BaiduComate13 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员
光辉GuangHui13 小时前
Agent Skill 也需要测试:如何搭建 Skill 评估框架
前端·后端·llm
我是谁的程序员13 小时前
Mac 上生成 AppStoreInfo.plist 文件,App Store 上架
后端·ios
irving同学4623813 小时前
Node 后端实战:JWT 认证与生产级错误处理
前端·后端
Master_Azur13 小时前
单元测试——Junit单元测试框架
后端
用户83562907805113 小时前
使用 Python 进行 Word 邮件合并
后端
用户83562907805113 小时前
Python 操作 PowerPoint OLE 对象
后端·python