MySQL为何不推荐用SELECT *,尤其在覆盖索引和IO优化场景下?

2026-04-30 21:270阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计975个文字,预计阅读时间需要4分钟。

MySQL为何不推荐用SELECT *,尤其在覆盖索引和IO优化场景下?

直接使用SELECT *会破坏覆盖索引,强制回表查询,这并非可能慢,而是必然慢,因为它是完全随机+I/O的过程。

为什么 SELECT * 必然让覆盖索引失效

覆盖索引生效的前提是:查询所需所有字段都完整存在于某个二级索引的叶子节点中。一旦用了 SELECT *,MySQL 就必须把整行数据捞出来——哪怕你只差一个 TEXTBLOB 字段没在索引里。

TEXTBLOB、超长 VARCHAR(超过 728 字节)根本不会被任何索引存储,MySQL 会静默忽略它们是否出现在联合索引定义中。

  • 执行计划里 type 还是 ref,但 ExtraUsing index 变成 Using where,就是最直接的信号:覆盖已失效
  • 哪怕你给所有“小字段”建了联合索引,只要表里存在 TEXT,这个索引就永远无法覆盖整行
  • 优化器不是“放弃索引”,而是被迫走“索引扫描 + 回表”,成本评估后可能干脆选全表扫描(顺序 I/O 比大量随机 I/O 更快)

大字段带来的额外 IO 开销

InnoDB 对大于 728 字节的字段会做行溢出处理:主记录只存 20 字节指针,真实内容存到单独的溢出页。这意味着读一行,要先读聚簇索引页,再根据指针去读溢出页——至少两次随机 I/O。

阅读全文
标签:Mysql

本文共计975个文字,预计阅读时间需要4分钟。

MySQL为何不推荐用SELECT *,尤其在覆盖索引和IO优化场景下?

直接使用SELECT *会破坏覆盖索引,强制回表查询,这并非可能慢,而是必然慢,因为它是完全随机+I/O的过程。

为什么 SELECT * 必然让覆盖索引失效

覆盖索引生效的前提是:查询所需所有字段都完整存在于某个二级索引的叶子节点中。一旦用了 SELECT *,MySQL 就必须把整行数据捞出来——哪怕你只差一个 TEXTBLOB 字段没在索引里。

TEXTBLOB、超长 VARCHAR(超过 728 字节)根本不会被任何索引存储,MySQL 会静默忽略它们是否出现在联合索引定义中。

  • 执行计划里 type 还是 ref,但 ExtraUsing index 变成 Using where,就是最直接的信号:覆盖已失效
  • 哪怕你给所有“小字段”建了联合索引,只要表里存在 TEXT,这个索引就永远无法覆盖整行
  • 优化器不是“放弃索引”,而是被迫走“索引扫描 + 回表”,成本评估后可能干脆选全表扫描(顺序 I/O 比大量随机 I/O 更快)

大字段带来的额外 IO 开销

InnoDB 对大于 728 字节的字段会做行溢出处理:主记录只存 20 字节指针,真实内容存到单独的溢出页。这意味着读一行,要先读聚簇索引页,再根据指针去读溢出页——至少两次随机 I/O。

阅读全文
标签:Mysql