共计 3067 个字符,预计需要花费 8 分钟才能阅读完成。
面试官:“小陈,说一下你罕用的 SQL 优化形式吧。”
陈小哈:“那很多啊,比方不要用 SELECT *,查问效率低。巴拉巴拉 …”面试官:“为什么不要用 SELECT *?它在哪些状况下效率低呢?”
陈小哈:“SELECT * 它如同比写指定列名多一次全表查问吧,还多查了一些无用的字段。”面试官:“嗯 …”
陈小哈:“emmm~ 没了”陈小哈:“….??(几个意思)”
面试官:“嗯 … 好,那你还有什么要问我的么?”
陈小哈:“我问你个锤子,把老子简历还我!”
无论在工作还是面试中,对于 SQL 中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但广泛了解还是在很浅的层面,并没有多少人去追本溯源,探索其原理。
废话不多说,本文带你深刻理解一下 ”SELECT * “ 效率低的起因及场景。
本文很干!请自备茶水,没工夫看记得先珍藏 — 来自一位被技术经理毒打多年的程序员的忠告
一、效率低的起因
先看一下最新《阿里 java 开发手册(泰山版)》中 MySQL 局部形容:
4 – 1.【强制】在表查问中,一律不要应用 * 作为查问的字段列表,须要哪些字段必须明确写明。
阐明:
- 减少查问分析器解析老本。
- 增减字段容易与 resultMap 配置不统一。
- 无用字段减少网络 耗费,尤其是 text 类型的字段。
开发手册中比拟概括的提到了几点起因,让咱们深刻一些看看:
1、不须要的列会减少数据传输工夫和网络开销
- 用“SELECT *”数据库须要解析更多的对象、字段、权限、属性等相干内容,在 SQL 语句简单,硬解析较多的状况下,会对数据库造成惨重的累赘。
- 增大网络开销;* 有时会误带上如 log、IconMD5 之类的无用且大文本字段,数据传输 size 会几何增涨。如果 DB 和应用程序不在同一台机器,这种开销非常明显
- 即便 mysql 服务器和客户端是在同一台机器上,应用的协定还是 tcp,通信也是须要额定的工夫。
2、对于无用的大字段,如 varchar、blob、text,会减少 io 操作
精确来说,长度超过 728 字节的时候,会先把超出的数据序列化到另外一个中央,因而读取这条记录会减少一次 io 操作。(MySQL InnoDB)
3、失去 MySQL 优化器“笼罩索引”策略优化的可能性
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 的大小和命中率),这种状况下,一个是内存读,一个是磁盘读,速度差别就很显著了,简直是数量级的差别。
=
二、索引常识延申
下面提到了辅助索引,在 MySQL 中辅助索引包含单列索引、联结索引,单列索引就不再赘述了,这里提一下联结索引的作用
● 联结索引 (a,b,c)
联结索引 (a,b,c) 理论建设了 (a)、(a,b)、(a,b,c) 三个索引;
咱们能够将组合索引想成书的一级目录、二级目录、三级目录,如 index(a,b,c),相当于 a 是一级目录,b 是一级目录下的二级目录,c 是二级目录下的三级目录。要应用某一目录,必须先应用其下级目录,一级目录除外。
如下:
where 条件
成果
where a=1 and c=1
只应用了一级目录,c 在三级目录,没有应用二级目录,那么三级目录就没法应用
where a=1 and b=1
只应用了一级目录、二级目录。
–
● 联结索引的劣势
1)缩小开销
建一个联结索引 (a,b,c),理论相当于建了 (a)、(a,b)、(a,b,c) 三个索引。每多一个索引,都会减少写操作的开销和磁盘空间的开销。对于大量数据的表,应用联结索引会大大的缩小开销!
2)笼罩索引
对联结索引 (a,b,c),如果有如下 sql 的,
SELECT a,b,c from table where a='xx' and b = 'xx';
那么 MySQL 能够间接通过遍历索引获得数据,而无需回表,这缩小了很多的随机 io 操作。缩小 io 操作,特地是随机 io 其实是 DBA 次要的优化策略。所以,在真正的理论利用中,笼罩索引是次要的晋升性能的优化伎俩之一。
3)效率高
索引列多,通过联结索引筛选出的数据越少。比方有 1000W 条数据的表,有如下 SQL:
select col1,col2,col3 from table
where col1=1 and col2=2 and col3=3;
假如:假如每个条件能够筛选出 10% 的数据。
- A. 如果只有单列索引,那么通过该索引能筛选出 1000W10%=100w 条数据,而后再回表从 100w 条数据中找到合乎 col2=2 and col3= 3 的数据,而后再排序,再分页,以此类推(递归);
- B. 如果是(col1,col2,col3)联结索引,通过三列索引筛选出 1000w10% 10% *10%=1w,效率晋升可想而知!
–
● 索引是建的越多越好吗
答案天然是否定的
- 数据量小的表不须要建设索引,建设会减少额定的索引开销
- 不常常援用的列不要建设索引,因为不罕用即便建设了索引也没有多大意义
- 常常频繁更新的列不要建设索引,因为必定会影响插入或更新的效率
- 数据反复且散布均匀的字段,因而他建设索引就没有太大的成果(例如性别字段,只有男女,不适宜建设索引)
- 数据变更须要保护索引,意味着索引越多保护老本越高。
- 更多的索引也须要更多的存储空间
三、心得体会
置信能看到这里这老铁要么是对 MySQL 有着一腔热血的,要么就是喜爱滚鼠标的。来了就是缘分,如果从本文学到了货色,请不要悭吝手中的赞哦,回绝白嫖~
有敌人问我,你对 SQL 标准那么上心,平时你写代码不会用 SELECT * 吧?
咋可能啊,天天用。。代码里也在用(一脸惭愧),其实咱们的我的项目广泛很小,数据量也上不去,性能上还没有遇到瓶颈,所以比拟放荡。
写本篇文章次要是这个知识点网上总结的很少很散,也不标准,算是给本人也是给大家总结一份比拟具体的,值得记一下的。当前给面试官说完让他没法找你茬。
往期举荐
手写一个“打飞机”小游戏附【源代码】[](http://mp.weixin.qq.com/s?__b…
一个基于 SpringBoot2 + MybatisPlus 的商城管理系统,真香~~
为啥《阿里开发手册》一律禁止应用 SELECT *?
Springboot+MybatisPlus 高效实现增删改查,写的切实太好了!!
七个开源的 Spring Boot 前后端拆散我的项目,肯定要珍藏!
值得举荐的十几款 IDEA 插件,大大晋升开发效率【值得珍藏】
【我的项目实战 + 源码】Java 身份证号码识别系统
10 个你可能未曾用过却很有用的 Linux 命令~
面试官:你能说出 办法重载和办法重写 的原理吗?
又发愁没我的项目?java + vue 的前后端拆散的考试零碎【附源码】
发愁没我的项目?用 Java 开发一个乏味的表情生成器【附源码】
如果感觉文章不错,能够在文末 点个赞