为什么大家都说 SELECT * 效率低?
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
无论在工作还是面试中,关于SQL中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但普遍理解还是在很浅的层面,并没有多少人去追根究底,探究其原理。
废话不多说,本文带你深入了解一下"SELECT * "效率低的原因及场景。
本文很干!请自备茶水,没时间看记得先收藏 -- 来自一位被技术经理毒打多年的程序员的忠告
一、效率低的原因
先看一下最新《阿里java开发手册(泰山版)》中 MySQL 部分描述:
4 - 1. 【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
说明:
增加查询分析器解析成本。
增减字段容易与 resultMap 配置不一致。
无用字段增加网络 消耗,尤其是 text 类型的字段。
开发手册中比较概括的提到了几点原因,让我们深入一些看看:
- 不需要的列会增加数据传输时间和网络开销
用“SELECT * ”数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
增大网络开销;* 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。如果DB和应用程序不在同一台机器,这种开销非常明显
即使 mysql 服务器和客户端是在同一台机器上,使用的协议还是 tcp,通信也是需要额外的时间。
- 对于无用的大字段,如 varchar、blob、text,会增加 io 操作
准确来说,长度超过 728 字节的时候,会先把超出的数据序列化到另外一个地方,因此读取这条记录会增加一次 io 操作。(MySQL InnoDB) - 失去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中辅助索引包括单列索引、联合索引(多列联合),单列索引就不再赘述了,这里提一下联合索引的作用。图解 MySQL 索引:B-树、B+树,这篇推荐看下。
联合索引 (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,效率提升可想而知!
索引是建的越多越好吗
答案自然是否定的
数据量小的表不需要建立索引,建立会增加额外的索引开销
不经常引用的列不要建立索引,因为不常用,即使建立了索引也没有多大意义
经常频繁更新的列不要建立索引,因为肯定会影响插入或更新的效率
数据重复且分布平均的字段,因此他建立索引就没有太大的效果(例如性别字段,只有男女,不适合建立索引)
数据变更需要维护索引,意味着索引越多维护成本越高。
更多的索引也需要更多的存储空间
三、心得体会
相信能看到这里这老铁要么是对MySQL有着一腔热血的,要么就是喜欢滚鼠标的。来了就是缘分,如果从本文学到了东西,请不要吝啬手中的赞哦,拒绝白嫖~
有朋友问我,你对SQL规范那么上心,平时你写代码不会用SELECT * 吧?
咋可能啊,天天用。。代码里也在用(一脸羞愧),其实我们的项目普遍很小,数据量也上不去,性能上还没有遇到瓶颈,所以比较放纵。
写本篇文章主要是这个知识点网上总结的很少很散,也不规范,算是给自己也是给大家总结一份比较详细的,值得记一下的。以后给面试官说完让他没法找你茬。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/zhibo立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-07-07
本文作者:互联网架构师
本文来自:“互联网架构师”,了解相关信息可以关注“互联网架构师”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
【云栖号直播】本周重磅:阿里云微服务引擎MSE2.0重磅升级发布会!
云栖号在线课堂,及时了解行业动态!阿里云推出疫情专题方案,为企业业务护航,让你足不出户了解行业动态。 在这里可以走近阿里云基础产品,了解更多应用方案,还能遇见大咖分享洞见及故事!也可以通过视频的形式让你高效、生动的了解场景化的上云最佳实践。 本周重磅推荐 标题:飞天大数据产品价值解读 — 全域数据综合开发与治理平台 DataWorks 简介:本次直播将为您介绍全域数据开发与综合治理平台 DataWorks如何助力企业数据中台建设,以及基于DataWorks建设数据中台的典型场景与解决方案。 观看直播 标题:阿里云微服务引擎MSE2.0重磅升级发布会 简介:微服务引擎MSE在原注册中心托管的基础上,新增配置中心托管和微服务治理功能,并通过先进的 Java Agent 技术使得您的应用无需修改任何代码和配置,兼容 Spring Cloud / Duboo 近 5 年的所有版本,客户可享有业内首个集服务注册、服务配置和服务治理于一体的非托管型 PaaS 产品。目前,配置中心不收费,治理中心公测期免费开放。 观看直播 标题:阿里云 & 移远通信 Cat 1新品发布会 简介:随着通信技...
- 下一篇
记一次生产环境存储过程优化的过程(42秒-->0.06秒)
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 概述 在拿awr报告时发现有一个存储过程效率很慢,执行要很长时间,所以在测试环境模拟,开始了我的优化之路..下面写一下我的整体优化步骤和优化后的效果。 1.存储过程如下:通过awr报告定位到这条问题存储过程。 2.分析存储过程:调试后分析大概需要42秒。 3、查看表数据量和定义数量级为144万。 4、改写sql查看执行计划因为update部分耗时比较多,所以考虑改写成select看有没走索引。 select updatetime,sendtootm from Tab_TempDriverScan where ScanWay = '1' and ShipmentNumber = v_shipmentnumber and LPN = idx.LPN and SKU = idx.SKU; 6、应用bulk collect优化改写后如下 TYPE Tab_TempDriverScan_rec_type IS RECORD --声明记录类型 ( v_shipmentnumber Tab_TempD...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Hadoop3单机部署,实现最简伪集群
- CentOS7,CentOS8安装Elasticsearch6.8.6