为什么不建议使用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)都包含在索引中,可以直接通过索引获取数据,无需回表操作。

相关推荐
葫芦和十三5 小时前
图解 MongoDB 28|块与迁移:balancer 怎么均衡数据
后端
葫芦和十三5 小时前
图解 MongoDB 27|分片策略:范围分片 vs 哈希分片
后端·mongodb·agent
paopaokaka_luck6 小时前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts
我叫黑大帅6 小时前
MySQL 并发插入竞态问题:原子写入实践指南
后端·mysql·面试
我会尽全力 乐观而坚强7 小时前
MySQL零基础入门(二)
数据库·mysql·adb
zhangxingchao7 小时前
AI大模型核心八:从 Agent Skill、长文档 RAG 到知识库更新与训练策略
前端·人工智能·后端
我叫黑大帅7 小时前
别再手动写 updated_at了,这坑我踩过
后端·面试·go
zhangxingchao8 小时前
AI大模型核心七:从 Workflow、RAG、记忆治理到幂等性
前端·人工智能·后端
犀利豆9 小时前
AI in Harness(二)
java·人工智能·后端
IT_陈寒9 小时前
Python装饰器竟然偷偷改了函数名?这个坑我爬了三天
前端·人工智能·后端