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

相关推荐
To_OC7 小时前
从一行入口代码啃透 NestJS:工厂模式、装饰器和依赖注入是怎么串起来的
后端·设计模式·nestjs
Python私教7 小时前
多个项目怎么安全合并?先适配,再切换
后端·python·架构
Python私教9 小时前
从表格到管理系统:别先写页面,先补齐权限、流程和审计
数据库·后端·架构
北斗落凡尘10 小时前
LangGraph 入门实战(12)--使用MCP
后端·python·langchain
NJCloud10 小时前
TiDB 集群部署与 MySQL 兼容性适配实战
linux·运维·数据库·mysql·tidb
SomeB1oody11 小时前
【RustyML入门】6.0. 数学工具
开发语言·后端·机器学习·rust·教程
IT_陈寒12 小时前
为什么我的JavaScript闭包总是漏掉那个变量?
前端·人工智能·后端
用户83562907805112 小时前
如何使用 Python 将 PowerPoint 转换为 PDF 文档
后端·python
倔强的石头_12 小时前
从 8 行报错到一条故障链:我用蓝耘 MaaS 做了一个 AI 日志分析助手
后端