基于本文回答

播面 播面

文解图解播客视频,多维讲透八股文
0
评论

当id 为主键时,select * from table where id =1 和 select id from table where id = 1 的效率是一样的吗?

知识点图片

在 MySQL(以最常用的 InnoDB 存储引擎为例)中,当 id 为主键时,这两条 SQL 的效率在绝大多数普通场景下差异极小,但在底层执行细节、资源开销以及特定表结构下,它们的效率是不一样的,SELECT id 往往会比 SELECT * 更高效

具体的效率差异和底层原理可以从以下几个维度来分析:

1. 相同的底层执行路径(相同点)

  • 索引寻路一致:在 InnoDB 中,主键 id聚簇索引(Clustered Index)。无论执行哪一条语句,MySQL 优化器都会判定为 const 类型(即最快的常量等值查询)。
  • B+ 树遍历一致:两者的执行都需要通过主键的 B+ 树索引,从根节点一路向下寻找到对应 id = 1 的叶子节点。
  • 基本 I/O 一致:如果要找的数据页(Page)不在内存的 Buffer Pool 中,两者都会触发一次相同的磁盘 I/O,将该行所在的数据页加载到内存中。

2. 不同的开销与处理细节(差异点)

一旦通过索引定位到了对应的行数据,两者的处理逻辑就产生了分歧,这导致了效率的差异:

① 溢出页(Overflow Pages)的磁盘 I/O 差异(关键影响)

  • 如果表中有 TEXTBLOB 或非常长的 VARCHAR 字段
    在 InnoDB 中,当单行数据过大时,大字段的数据不会直接存放在聚簇索引的叶子节点内,而是被存放在单独的溢出页(Off-page)中,叶子节点只保留指向溢出页的指针。
    • SELECT id:由于只需要 id 字段,MySQL 绝对不会去读取这些大字段的溢出页。
    • SELECT *:因为要求返回所有字段,MySQL 必须顺着指针去额外读取这些溢出页,这会产生额外的磁盘或内存 I/O。在这种情况下,SELECT * 的性能会明显下降。

② 内存与 CPU 解析开销

  • SELECT id
    由于 WHERE id = 1 已经限定了主键值,在 MySQL 的优化阶段,优化器甚至直接就能确定 id 的值,引擎层只需确认该行存在,不需要对行数据进行复杂的反序列化。
  • SELECT *
    InnoDB 的行数据是以特定格式存储的。MySQL 必须在内存中把整行数据进行解析和拆解(Unpacking),将各个字段的值提取出来并拷贝到服务层的行缓冲区中。如果表的列数非常多,这个过程会消耗更多的 CPU 和内存。

③ 网络传输带宽

  • SELECT id:只传输一个整数(如 INT 占 4 字节,BIGINT 占 8 字节),网络报文极小。
  • SELECT *:需要将该行的所有列数据通过网络发送给客户端。如果单行数据较大(如几 KB 到 几 MB),在高并发场景下,网络带宽和网卡 I/O 很容易成为瓶颈。

总结

  • 在字段较少、没有大字段的简单表中,这两者的执行时间差异通常在微秒级别,在应用层几乎无法感知。
  • 在包含大字段(TEXT/BLOB)、多列(数十甚至上百列)或高并发的场景下SELECT id 的效率会明显优于 SELECT *

因此,从数据库最佳实践和性能优化的角度出发,即使是主键点查询,也依然强烈建议**“按需查询”,避免无脑使用 SELECT ***。