当id 为主键时,select * from table where id =1 和 select id from table where id = 1 的效率是一样的吗?
SELECT id比SELECT *更高效。因为id是主键,SELECT id可利用“索引覆盖”,直接从索引获取数据,无需读取整行记录,从而减少了磁盘 I/O 和网络传输开销。
在 MySQL 中,这两条语句的效率是 不一样 的,select id from table where id = xxx 的效率会 更高。
尽管对于单行查询,这种差异在大多数情况下微乎其微,甚至难以察觉,但在数据库设计的原理层面,理解这个差异至关重要。
下面我们来详细解释为什么。
核心原因:数据获取的范围不同
这两条 SQL 语句的执行过程可以分为两个主要阶段:
- 数据定位(Finding):通过索引找到目标数据行的位置。
- 数据获取与传输(Fetching & Transferring):读取数据并将其返回给客户端。
1. 数据定位阶段:效率完全相同
- 因为
id是主键,MySQL 会使用 主键索引(在 InnoDB 中是聚簇索引)来定位数据。 - 无论是
SELECT *还是SELECT id,它们的WHERE id = xxx条件是完全一样的。 - 因此,MySQL 都会通过 B+Tree 索引进行一次极速的查找操作,直接定位到
id = xxx对应的数据行的物理存储位置。 - 在这个阶段,两者的速度和消耗是 完全相同 的。
2. 数据获取与传输阶段:效率差异巨大
这是两者效率差异的根本所在。
SELECT id FROM table WHERE id = xxx- 利用了“索引覆盖”(Covering Index)。
- 当 MySQL 通过主键索引找到
id = xxx的条目时,它需要的数据(id本身)已经在索引树的节点上了。 - 数据库引擎不需要再去访问磁盘上的数据页来读取完整的行数据。它直接从索引中获取
id值,然后就可以返回结果了。 - 这个过程避免了对表数据的二次读取,I/O 开销极小。
- 传输给客户端的数据量也极小(只有一个
id值)。
SELECT * FROM table WHERE id = xxx- MySQL 同样通过主鍵索引定位到数据行的位置。
- 但是,由于你需要
*(所有列),数据库引擎必须:- 读取整行数据:根据索引定位到的地址,去数据页(Data Page)中读取该行的所有列的数据。如果这张表有很多列,或者包含
TEXT、BLOB等大字段,这一步的 I/O 开销会显著增加。 - 网络传输:将所有列的数据通过网络传输给客户端。数据量越大,网络传输的耗时就越长。
- 读取整行数据:根据索引定位到的地址,去数据页(Data Page)中读取该行的所有列的数据。如果这张表有很多列,或者包含
总结与对比
| 对比维度 | SELECT id FROM table WHERE id = xxx |
SELECT * FROM table WHERE id = xxx |
|---|---|---|
| 1. 查找方式 | 主键索引查找 | 主键索引查找 |
| 2. 查找效率 | 相同 | 相同 |
| 3. 数据读取 | 只读取索引,不访问表数据(索引覆盖) | 读取索引定位到的完整行数据 |
| 4. I/O 消耗 | 极低 | 更高(取决于行数据大小) |
| 5. 网络传输量 | 极小 | 更大(取决于行数据大小) |
| 6. 整体效率 | 更高 | 更低 |
什么时候差异会很明显?
在以下情况下,SELECT * 带来的性能损耗会非常明显:
- 表列数非常多:几十上百个列。
- 表中包含大字段:如
VARCHAR(4000),TEXT,BLOB等。 - 查询非常频繁:在高并发场景下,这点额外的 I/O 和网络开销会被放大,成为系统瓶颈。
- 网络环境较差:客户端和数据库服务器之间的网络延迟高或带宽低。
结论与最佳实践
结论:SELECT id 比 SELECT * 更高效,因为它利用了索引覆盖,减少了 I/O 操作和网络传输量。
最佳实践:在任何时候,都应该遵循 “按需索取” 的原则。只查询你需要的列,而不是为了方便使用 SELECT *。这是一种非常重要的 SQL 优化习惯,可以有效提升数据库性能,降低服务器负载。
右滑查看面试常问