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

相关推荐
NightDW2 小时前
amqp-client源码解析1:数据格式
java·后端·rabbitmq
程序员清风3 小时前
美团二面:KAFKA能保证顺序读顺序写吗?
java·后端·面试
风象南4 小时前
SpringBoot的零配置API文档工具的设计与实现
spring boot·后端
程序员爱钓鱼4 小时前
Go语言实战案例-项目实战篇:开发一个 IP 归属地查询接口
后端·google·go
追逐时光者4 小时前
C#/.NET/.NET Core推荐学习书籍(25年9月更新)
后端·.net
IT_陈寒4 小时前
Vue3性能优化:掌握这5个Composition API技巧让你的应用快30%
前端·人工智能·后端
canonical_entropy14 小时前
从同步范式到组合范式:作为双向/δ-lenses泛化的可逆计算理论
后端·低代码·领域驱动设计
Funcy14 小时前
XxlJob 源码分析06:任务执行流程(一)之调度器揭秘
后端
AAA修煤气灶刘哥15 小时前
数据库优化自救指南:从SQL祖传代码到分库分表的骚操作
数据库·后端·mysql