不管是上班还是面试,SQL中不使用“SELECT*”的问题是大家耳熟能详的问题。追根究底,探究其原理。图片来自Pexels面试官:“小陈,说说你常用的SQL优化方法吧。”陈小哈:“那很多,比如不要用SELECT*,查询效率低。芭芭拉……”面试官:“为什么不用SELECT*?什么情况下效率低?”陈小哈:“SELECT*好像比写指定列名多了一个全表查询,还查了一些没用的字段。”面试官:“嗯……”陈小哈:“emmm~没了”陈小哈:“.....?我求你个锤子,简历还给我!”废话不多说,本文带你了解“SELECT*”效率低下的原因和场景。这篇文章很干!请自带茶水。如果你没有时间阅读它,记得先收藏它。一个被技术经理打了多年的程序员的忠告!效率低下的原因看《阿里 Java 开发手册(泰山版)》最新的MySQL部分说明:4-1.【强制】在表查询中,千万不要使用*作为查询的字段列表,哪些字段必须是必填项明确提出。说明:增加查询分析器的解析成本。加减字段容易和resultMap配置不一致。无用的字段会增加网络消耗,尤其是文本类型的字段。开发手册中提到了几个原因,让我们深入了解一下:①不必要的列会增加数据传输时间和网络开销。总结了以下三点:使用“SELECT*”数据库需要解析较多的对象、字段、权限、属性等相关内容,在SQL语句复杂、硬解析较多的情况下,会对数据库造成沉重的负担。增加网络开销;*有时会错误地包含log、IconMD5等无用且较大的文本字段,数据传输量会呈几何级数增长。如果DB和应用不在同一台机器上,这个开销是非常明显的。即使MySQL服务器和客户端在同一台机器上,使用的协议仍然是TCP,通信需要额外的时间。②对于无用的大字段,比如varchar、blob、text,会增加IO操作。准确的说,当长度超过728字节时,多余的数据会先被序列化到另一个地方,所以读取这条记录会增加一个IO操作。(MySQLInnoDB)③失去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+树的查询,速度必然会慢很多。由于辅助索引的数据量远小于聚簇索引,所以很多情况下,覆盖索引是通过辅助索引进行的(用户需要的所有列都可以通过索引获取),没有需要读磁盘,直接从内存中访问。聚集索引很可能在磁盘(外存)中有数据(取决于缓冲池的大小和命中率)。在这种情况下,一个是内存读取,另一个是磁盘读取。速度差异非常显着,几乎是一个数量级的差异。索引知识扩展在上面提到了辅助索引。在MySQL中,辅助索引包括单列索引和联合索引(多列联合)。单列索引这里不做详细介绍。这里要提到联合索引的作用。联合索引(a,b,c)联合索引(a,b,c)实际上创建了三个索引(a),(a,b),(a,b,c)。我们可以把组合索引看成是一本书的一级目录、二级目录、三级目录,比如index(a,b,c)。相当于a是一级目录,b是一级目录下的二级目录,c是二级目录下的三级目录。要使用一个目录,首先要使用它的父目录,一级目录除外。如下图所示:联合索引的优点联合索引的优点如下:①减少开销,构建联合索引(a,b,c),其实等同于构建(a),(a,b),(a,b,c)三个指标。每个额外的索引都会增加写操作和磁盘空间的开销。对于数据量很大的表,使用联合索引会大大减少开销!②为联合索引(a,b,c)覆盖索引,如果有如下SQL:SELECTa,b,cfromtablewherea='xx'andb='xx';那么MySQL可以直接遍历索引获取数据,不需要回表,减少了很多随机IO操作。减少IO操作,尤其是随机IO,其实是DBA们的主要优化策略。因此,在实际应用中,覆盖索引是提高性能的主要优化手段之一。③效率高,索引列越多,通过联合索引过滤的数据越少。比如一张有1000W条数据的表,SQL如下:selectcol1,col2,col3fromtablewherecol1=1andcol2=2andcol3=3;假设:假设每个条件都能过滤掉10%的数据。A:如果只有单列索引,那么可以通过这个索引筛选出1000W10%=100w条数据,然后回表从表中找到满足col2=2和col3=3的数据100W条数据,然后排序分页到等等(递归)。B:如果是(col1,col2,col3)联合索引,通过三列索引过滤掉1000W10%10%*10%=1W,效率提升可想而知!建立更多的索引更好吗?答案自然是否定的:数据量小的表不需要建索引,建索引会增加额外的索引开销。不要为不经常引用的列建立索引,因为它们不常用,即使建立索引也没有多大意义。不要为频繁更新的列创建索引,因为它肯定会影响插入或更新的效率。数据重复且分布均匀的字段,因此建立索引没有太大作用(例如性别字段,只有男性和女性,不适合建立索引)。数据变化需要维护索引,也就是说索引越多,维护成本越高。更多的索引也需要更多的存储空间。相信看得出来,这位老哥要么对MySQL充满热情,要么就是喜欢滚鼠标。有朋友问我,你这么在意SQL规范,写代码一般不会用SELECT*吧?怎么可能,你天天用!代码中也用到了(一脸惭愧),其实我们的项目一般都比较小,数据量上不去,性能也没有遇到瓶颈,所以比较放纵。写这篇文章的主要原因是网上对这个知识点的总结很少是零散的,不规范的。算是对自己和大家比较详细的总结,值得回味。稍后告诉面试官,以免他挑剔你!作者:陈哈哈编辑:陶家龙来源:https://urlify.cn/ZvM3qe
