从零开始搞懂 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 就能秒懂啦!

相关推荐
浪九天3 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
uhakadotcom4 小时前
Apache CXF 中的拒绝服务漏洞 CVE-2025-23184 详解
后端·面试·github
uhakadotcom4 小时前
CVE-2025-25012:Kibana 原型污染漏洞解析与防护
后端·面试·github
uhakadotcom4 小时前
揭秘ESP32芯片的隐藏命令:潜在安全风险
后端·面试·github
uhakadotcom4 小时前
Apache Camel 漏洞 CVE-2025-27636 详解与修复
后端·面试·github
uhakadotcom4 小时前
OpenSSH CVE-2025-26466 漏洞解析与防御
后端·面试·github
uhakadotcom4 小时前
PostgreSQL的CVE-2025-1094漏洞解析:SQL注入与元命令执行
后端·面试·github
zhuyasen5 小时前
Go语言开发实战:app库实现多服务启动与关闭的优雅方案
后端·go
ITlinuxP5 小时前
2025最新Postman、Apipost和Apifox API 协议与工具选择方案解析
后端·测试工具·postman·开发工具·apipost·apifox·api协议
计算机-秋大田5 小时前
基于Spring Boot的宠物健康顾问系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计