SELECT * 在绝大多数生产场景下都不该用,核心问题在于它同时破坏网络效率和索引优化能力:触发多次socket写入、禁用覆盖索引、导致回表、放大字段变更与权限风险。

直接说结论:SELECT * 在绝大多数生产场景下都不该用,核心问题不在语法本身,而在它会同时破坏网络效率和索引优化能力——这两点在高并发、大数据量时会被急剧放大。
网络传输开销远超直觉
很多人以为“反正都是查一行”,但SELECT * 会把所有字段塞进每次 net_buffer(默认仅 16KB),一旦表里有 TEXT、BLOB 或长 VARCHAR 字段,单行数据就可能触发多次 socket send buffer 写入。更关键的是:
- MySQL 不会压缩结果集,原始字节全量走 TCP;DB 和应用若跨机房,延迟直接翻倍
- 应用层反序列化成本上升:比如 Java 的 ORM 拿到 20 个字段却只用 3 个,仍要构造完整对象、触发 GC
-
SELECT *让查询计划无法预估返回体积,优化器可能误判为“小结果集”而跳过流式处理逻辑
覆盖索引完全失效
只要查询字段能被某个索引“全包住”,InnoDB 就不必回表读聚簇索引——这就是覆盖索引的价值。而 SELECT * 天然打破这个前提:
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 即使你建了
KEY IDX_NAME_PHONE (name, phone),SELECT name, phone FROM user_innodb WHERE name = 'Alice'能走覆盖索引;但SELECT * FROM user_innodb WHERE name = 'Alice'一定回表,因为id和gender不在该索引中 - 复合索引顺序敏感:
SELECT id, name可能用上主键索引,但SELECT *会强制读取整行,哪怕id已是主键 - EXPLAIN 中看到
type: ALL或Extra: Using where; Using index condition但没出现Using index,基本就是被*拖累
字段变更带来的隐性风险
表结构不是静态的,而 SELECT * 把字段顺序、类型、数量全部交给数据库运行时决定:
- 新增
JSON字段后,旧应用可能因 JSON 解析失败直接抛SQLException - ORM 映射依赖字段顺序(如 MyBatis 的
resultMap用下标绑定),列序一变,name可能映射成phone - 权限控制失效:DBA 给某用户只开了
SELECT(name, phone)权限,SELECT *直接越权读出password_hash
最常被忽略的一点:SELECT * 看似省事,实则把性能、安全、可维护性的决策权交给了数据库和时间——而这两者从不主动提醒你哪里错了。










