为何你们都说 SELECT * 效率低

“面试官:“小陈,说一下你经常使用的SQL优化方式吧。” 陈小哈:“那不少啊,好比不要用SELECT ,查询效率低。巴拉巴拉...”面试官:“为何不要用SELECT ?它在哪些状况下效率低呢?” 陈小哈:“SELECT * 它好像比写指定列名多一次全表查询吧,还多查了一些无用的字段。”面试官:“嗯...” 陈小哈:“emmm~ 没了”陈小哈:“....??(几个意思)”面试官:“嗯...好,那你还有什么要问个人么?” 陈小哈:“我问你个锤子,把老子简历还我!”
在这里插入图片描述
不管在工做仍是面试中,关于SQL中不要用“SELECT *”,都是你们听烂了的问题,虽然说听烂了,但广泛理解仍是在很浅的层面,并无多少人去追根究底,探究其原理。java

废话很少说,本文带你深刻了解一下"SELECT * "效率低的缘由及场景。mysql

1、效率低的缘由面试

先看一下最新《阿里java开发手册(泰山版)》中 MySQL 部分描述:sql

4 - 1. 【强制】在表查询中,一概不要使用 * 做为查询的字段列表,须要哪些字段必须明确写明。说明:数据库

  • 增长查询分析器解析成本。
  • 增减字段容易与 resultMap 配置不一致。
  • 无用字段增长网络 消耗,尤为是 text 类型的字段。

开发手册中比较归纳的提到了几点缘由,让咱们深刻一些看看:服务器

1.不须要的列会增长数据传输时间和网络开销网络

一、用“SELECT * ”数据库须要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的状况下,会对数据库形成沉重的负担。tcp

二、增大网络开销;* 有时会误带上如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的大小和命中率),这种状况下,一个是内存读,一个是磁盘读,速度差别就很显著了,几乎是数量级的差别。
在这里插入图片描述
2、索引知识延申

上面提到了辅助索引,在MySQL中辅助索引包括单列索引、联合索引(多列联合),单列索引就再也不赘述了,这里提一下联合索引的做用

联合索引 (a,b,c)

联合索引 (a,b,c) 实际创建了 (a)、(a,b)、(a,b,c) 三个索引

咱们能够将组合索引想成书的一级目录、二级目录、三级目录,如index(a,b,c),至关于a是一级目录,b是一级目录下的二级目录,c是二级目录下的三级目录。要使用某一目录,必须先使用其上级目录,一级目录除外。

以下:
在这里插入图片描述
联合索引的优点

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,效率提高可想而知!

索引是建的越多越好吗

答案天然是否认的

  • 数据量小的表不须要创建索引,创建会增长额外的索引开销
  • 不常常引用的列不要创建索引,由于不经常使用,即便创建了索引也没有多大意义
  • 常常频繁更新的列不要创建索引,由于确定会影响插入或更新的效率
  • 数据重复且分布平均的字段,所以他创建索引就没有太大的效果(例如性别字段,只有男女,不适合创建索引)
  • 数据变动须要维护索引,意味着索引越多维护成本越高。
  • 更多的索引也须要更多的存储空间

3、心得体会
相信能看到这里这老铁要么是对MySQL有着一腔热血的,要么就是喜欢滚鼠标的。来了就是缘分,若是从本文学到了东西,请不要吝啬手中的赞哦,拒绝白嫖~

有朋友问我,你对SQL规范那么上心,平时你写代码不会用SELECT * 吧?

咋可能啊,每天用。。代码里也在用(一脸羞愧),其实咱们的项目广泛很小,数据量也上不去,性能上尚未遇到瓶颈,因此比较放纵。

写本篇文章主要是这个知识点网上总结的不多很散,也不规范,算是给本身也是给你们总结一份比较详细的,值得记一下的。之后给面试官说完让他无法找你茬

顺便吹波牛B,谢谢各位。

来源:blog.csdn.net/qq_39390545/article/details/106766965