为什么不建议使用SELECT * ?

"避免使用SELECT *"已成为MySQL数据库操作中的一项重要准则,甚至连《阿里Java开发手册》也明确禁止将作为查询字段列表。

在实际开发过程中,可能会有小伙伴贪图方便,直接用*号代替了要返回的字段,特别是后期发现要添加返回的字段时,无需改动sql语句,可是这是一种不好的做法,接下来说说理由。

1.增加磁盘I/O开销

使用select * 会导致增加磁盘I/O的开销,特别是包含那种大字段的时候,可能现在表中就十个字段,可是随着业务的发展,表字段增加到了六十个,可是你这里的需求根本就不需要那几十个字段的,但是就因为你这里写的是select *,导致把那些多余的字段都给查出来了。在mysql中,数据通常都是存储在磁盘上的,因此查询操作是会涉及到磁盘I/O的。查询的字段增多,要读取的内容自然会增多,磁盘I/O的开销自然相应的增大,尤其是那种TEXT、LONGTEXT、MEDIUMTEXT大字段类型,这种影响更加明显。

2.增加网络时延

当数据库查询返回的字段数量增加(尤其是包含大字段如TEXTBLOB等)时,数据包体积会显著增大,导致以下问题:

  1. ‌网络传输次数增加:

    • 大字段可能超出TCP单次传输的最大数据包(MTU)限制,需分片传输,增加往返次数(RTT)‌。

    • 例如,MySQL默认的max_allowed_packet为64MB(mysql版本不同,这个值可能不同,可以通过show variables like 'max_allowed_packet'命令去进行确认),若查询结果超过此值,需多次传输‌。

  2. ‌时延累积:

    • 即使在同一台机器上,TCP协议仍需完成三次握手、数据确认等流程,每次传输均引入微秒级延迟‌。

3.无法利用覆盖索引

select *这种写法是会导致无法利用覆盖索引的。我们举个例子来说明这个问题,假设我们有一张user_info表,表的存储引擎用的是InnoDB,表字段都有id、age、name、address,id为主键,我们添加一个名为idx_age_name的联合索引,涵盖了age和name两个字段。

下面是查询语句:

sql 复制代码
select * from user_info where age = 18;

我们可以用explain命令去查看sql语句的执行计划,id主键索引树的叶子节点会包含完整的用户信息字段。

通过执行计划可以看到,是没有用上覆盖索引的,只是使用上了idx_age_name这个索引,但是这个索引里面没有包含address字段(我们的表里面是有address字段的,这里使用了*,代表查出表中的所有字段),所以还需要进行回表,回到主键索引树中找到address字段。

通过执行计划可以看到,如果我们只需要查出age字段和name字段的话,那就写select age,name 就好了,加上我们建有idx_age_name这个联合索引,这样就可以用上覆盖索引这个特性了。

Using index表示查询的列被索引覆盖,因而无需再回表

注意:覆盖索引其实不是一种独立的索引类型,而是一种查询优化的方式。简单说就是当查询的所有字段都包含在索引中时,就可以直接从索引中获取数据,就不需要去回表查询了。比如上面那个例子,因为查询字段(age、name)都包含在索引中,可以直接通过索引获取数据,无需回表操作。

相关推荐
Hooray38 分钟前
2026年,站在职业生涯十字路口的我该何去何从?
前端·后端
唐叔在学习43 分钟前
还在申请云服务器来传输数据嘛?试试P2P直连吧
后端·python
开心猴爷1 小时前
iOS 代码混淆在项目中的方式, IPA 级保护实践记录
后端
魅影骑士00101 小时前
柯里化函数
后端·设计模式
JOEH602 小时前
🛡️ 微服务雪崩救星:Sentinel 限流熔断实战,3行代码搞定高可用!
后端·全栈
想唱rap2 小时前
表的约束条件
linux·数据库·mysql·ubuntu·bash
aiopencode2 小时前
iOS手动代码混淆函数和变量名基本原理和注意事项教程
后端
程序员威哥2 小时前
YOLOv8用ConvMixer结构:简化Backbone,速度+20%,mAP仅降0.9%
后端
开心猴爷2 小时前
如何在苹果手机上面进行抓包?iOS代理抓包,数据流抓包
后端
程序员威哥2 小时前
轻量型YOLO入门:在嵌入式设备上跑通目标检测(树莓派实战)
后端