从零开始搞懂 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', '[email protected]'),
(2, 'Bob', '[email protected]'),
(3, 'Charlie', '[email protected]');

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

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 = '[email protected]';

    没索引,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 就能秒懂啦!

相关推荐
就叫飞六吧2 分钟前
Spring Security 集成指南:避免 CORS 跨域问题
java·后端·spring
冼紫菜1 小时前
[特殊字符]CentOS 7.6 安装 JDK 11(适配国内服务器环境)
java·linux·服务器·后端·centos
秋野酱3 小时前
Spring Boot 项目的计算机专业论文参考文献
java·spring boot·后端
香饽饽~、3 小时前
【第二篇】 初步解析Spring Boot
java·spring boot·后端
你是狒狒吗3 小时前
消息队列了解一哈
后端
Chandler244 小时前
Go语言 GORM框架 使用指南
开发语言·后端·golang·orm
蚂蚁在飞-5 小时前
Golang基础知识—cond
开发语言·后端·golang
程序员爱钓鱼11 小时前
匿名函数与闭包(Anonymous Functions and Closures)-《Go语言实战指南》原创
后端·golang
言之。12 小时前
Go 语言中接口类型转换为具体类型
开发语言·后端·golang