发布时间:2022-11-19 10:00
Hi ! 我是小小,今天带来本周的第三篇。为什么大家都在说 Select * 效率低。
面试官:“小小啊,说一说你常用的SQL优化方式吧”。
小小:“很多的,相当多,比如不要用SELECT,查询效率低,巴拉巴拉。。。”
面试官:“为什么不要用 SELECT* ?它在那些情况下效率低呢?”
小小:“SELECT * 它好像比写指定列多一次全表查询吧,还多查了一些无用的字段。”
面试官:“嗯?”
小小:“emememem~ 没了”
小小:“...??????”
面试官:“嗯,你还有什么药问的”
小小:“没了,我问你个锤子,赶紧把简历给我”
下面开始进入正题,
用SELECT * 数据库需要解析更多的对象,字段,权限,属性等等相关内容,在SQL语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
增大网络开销,* 有时会误操作,带上log,icomMD%等之类的无用且大的文本字段,数据传输size会几何的增长,如果DB和应用程序不在同一台机器,这种开销相当的明显
即使 Mysql 服务器和客户端在同一台机器上,使用的协议还是 tcp,通信也需要额外的时间。
正确来说,长度操作728字节的时候,会先把超出的数据序列化到另外一个地方,因此肚脐去的时候,这条记录会增加一次io操作。
SELECT * 杜绝了覆盖索引的可能性,而基于 MySQL 优化器的“覆盖索引”策略又是速度极快,效率极高,业界极为推荐的查询优化方式。
例如,有一个表为 t(a,b,c,d,e,f),其中,a 为主键,b 列有索引。
那么,在磁盘上有两棵 B+ 树,即聚集索引和辅助索引(包括单列索引、联合索引),分别保存(a,b,c,d,e,f)和(a,b)。
如果查询条件中 where 条件可以通过 b 列的索引过滤掉一部分记录,查询就会先走辅助索引;如果用户只需要 a 列和 b 列的数据,直接通过辅助索引就可以知道用户查询的数据。
如果用户使用 SELECT *,获取了不需要的数据,则首先通过辅助索引过滤数据,然后再通过聚集索引获取所有的列,这就多了一次 B+ 树查询,速度必然会慢很多。
由于辅助索引的数据比聚集索引少很多,很多情况下,通过辅助索引进行覆盖索引(通过索引就能获取用户需要的所有列),都不需要读磁盘,直接从内存取。
而聚集索引很可能数据在磁盘(外存)中(取决于 buffer pool 的大小和命中率),这种情况下,一个是内存读,一个是磁盘读,速度差异就很显著了,几乎是数量级的差异。
使用 SELECT * 时候,不熟悉代码库的人将会被迫查询文档,以了解能够进行有效更改之前需要返回那些列,从长远来看,使得代码更不具有可读性,从而耗费了更多的时间和精力。
如果代码取决于列顺序,SELECT * 则如果表的列顺序已经更改,则会隐藏等待发生的错误。
使用时配置更加复杂化。
select * 是反设计模式。
查询的目的不太明显,应用程序使用的列是不透明的,打破的列的模块化设计。
我是小小,一个生于二线,活在一线的程序猿,我是小小,我们下期再见。
小明菜市场
推荐阅读
● k8s | 搞不明白为什么大家都在学习 k8s
● 对战 | RabbitMq 大战 kafka
● 执行流程 | 你真的了解Spring AOP的执行顺序吗?
● 吊打面试官 | Java到底是值传递还是引用传递
● 容器 | Docker 如此之好,你为什么还要用k8s
给我个好看再走好吗?