到底是什么原因才导致 select * 效率低下的?
面试官:“小陈,说一下你常用的SQL优化方式吧。”
陈小哈:“那很多啊,比如不要用SELECT *,查询效率低。巴拉巴拉...”面试官:“为什么不要用SELECT * ?它在哪些情况下效率低呢?”
陈小哈:“SELECT * 它好像比写指定列名多一次全表查询吧,还多查了一些无用的字段。”面试官:“嗯...”
陈小哈:“emmm~ 没了”陈小哈:“....??(几个意思)”
面试官:“嗯...好,那你还有什么要问我的么?”
陈小哈:“我问你个锤子,把老子简历还我!”
无论在工作还是面试中,关于SQL中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但普遍理解还是在很浅的层面,并没有多少人去追根究底,探究其原理。
废话不多说,本文带你深入了解一下"SELECT * "效率低的原因及场景。
本文很干!请自备茶水,没时间看记得先收藏 -- 来自一位被技术经理毒打多年的程序员的忠告
目录
一、效率低的原因
1. 不需要的列会增加数据传输时间和网络开销
2. 对于无用的大字段,如 varchar、blob、text,会增加 io 操作
3. 失去MySQL优化器“覆盖索引”策略优化的可能性
二、索引知识延申
● 联合索引 (a,b,c)
● 联合索引的优势
1) 减少开销
2)覆盖索引
3)效率高
● 索引是建的越多越好吗
三、心得体会
一、效率低的原因
先看一下最新《阿里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是二级目录下的三级目录。要使用某一目录,必须先使用其上级目录,一级目录除外。
如下:
联合索引的优势
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 * 吧?
咋可能啊,天天用。。代码里也在用(一脸羞愧),其实我们的项目普遍很小,数据量也上不去,性能上还没有遇到瓶颈,所以比较放纵。
写本篇文章主要是这个知识点网上总结的很少很散,也不规范,算是给自己也是给大家总结一份比较详细的,值得记一下的。以后给面试官说完让他没法找你茬。
顺便吹波牛B,谢谢各位。
注:《阿里Java开发手册》-泰山版.pdf 电子书,
链接:https://pan.baidu.com/s/1GM2IRyI4_8s5fGURy3BEbg
密码:hmt6 有可能会失效
另外准备了500套应用实战代码,关注二维码微信公众号,回复「java」获取(链接失效后关注下方微信公众号,回复「java」获取到微信给你发送)
到底是什么原因才导致 select * 效率低下的?相关推荐
- 同一目录下有大量文件会影响效率吗_到底是什么原因才导致 select * 效率低下的?
面试官:"小陈,说一下你常用的SQL优化方式吧." 陈小哈:"那很多啊,比如不要用SELECT *,查询效率低.巴拉巴拉..." 面试官:"为什么不要 ...
- 导致MySQL的查询语句效率低下的可能原因
前言 本文来自于网络的拼凑,目的在于面试时可以让大家 pretend to be something (zhuang bi) . 一.执行语句执行效率低下的原因 ① SQL语句本身没那么慢,但是在某些 ...
- mysql越筛越少_面试官:为什么SELECT * 会导致查询效率低?
面试官:"小陈,说一下你常用的SQL优化方式吧." 陈小哈:"那很多啊,比如不要用SELECT *,查询效率低.巴拉巴拉..." 面试官:"为什么不要 ...
- SELECT TOP 1 比不加TOP 1 慢的原因分析以及SELECT TOP 1语句执行计划预估原理
现实中遇到过到这么一种情况: 在某些特殊场景下:进行查询的时候,加了TOP 1比不加TOP 1要慢(而且是慢很多)的情况, 也就是说对于符合条件的某种的数据,查询1条(符合该条件)数据比查询所有(符合 ...
- 十五天精通WCF——第七天 Close和Abort到底该怎么用才对得起观众
原文:十五天精通WCF--第七天 Close和Abort到底该怎么用才对得起观众 一:文起缘由 写这一篇的目的源自于最近看同事在写wcf的时候,用特别感觉繁琐而且云里雾里的嵌套try catch来防止 ...
- 到底多大并发才算高并发?一文带你全面认识高并发!
点击上方蓝色小字,关注"涛哥聊Python" 重磅干货,第一时间送达 作者 | 骆俊武 来源 | IT人的职场进阶 高并发,几乎是每个程序员都想拥有的经验.原因很简单:随着流量变大 ...
- 到底多大并发才算高并发?
高并发,几乎是每个程序员都想拥有的经验.原因很简单:随着流量变大,会遇到各种各样的技术问题,比如接口响应超时.CPU load升高.GC频繁.死锁.大数据量存储等等,这些问题能推动我们在技术深度上不断 ...
- app模式会被第三方平台模式取代吗_4大原因会导致App被下架,你中招了吗?
纵观2018全年,App下架远超新增,数量高达80W+,且下半年呈上升趋势,12月达到顶峰,App Store的监管可谓是越来越严. 3月,知乎由于传播不合规的信息被下架一周: 4月,今日头条.凤凰新 ...
- 火锅店搞活动火遍全国,但是不到一个月就关门了,到底是什么原因
很多餐饮店为了吸引流量,都会用各种引人注目的噱头大搞活动,希望通过这样的活动提高一下人气. 活动做得好,人气有了,生意也提高了,但是如果做不好,虽然生意火爆得不得了,但是最后还要亏很多钱,甚至亏到倒闭 ...
最新文章
- 2018年Python开源项目Top100!只在这里!
- MySQL-Front,MySQL的企业管理器
- exsi5.5安装过程中遇到的一个问题
- cobbler安装和基本配置
- [Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性
- Linux 指令的分类 (man page 可查看)
- autojs定时可以选定日期吗_微信怎么定时发送朋友圈——软件教程
- hive导数据到mysql 自增主键出错_python+mysql做一个图书管理系统?
- bootstrap 3.0 LESS源代码浅析(一)
- 日处理20亿数据,实时用户行为服务系统架构实践
- 2021百度之星程序设计大赛-初赛一部分题目总结
- MAX232芯片的引脚图和电脑串口的连接电路及RS232引脚定义详细说明
- 2019南京“无房证明”办理
- gin endless 热重启
- 基于WEMOS的智能WiFi避障小车
- 攻防世界mfw_攻防世界-Web-mfw
- 20189220余超 团队博客——阅读软件app
- BJOI2019 奥术神杖
- ios上架图片在线制作_IOS上架证书制作,ipa打包,Transporter上传
- java如何实现qq分组_Android仿QQ好友列表分组实现增删改及持久化
热门文章
- C#基础(四)--值类型和引用类型,栈和堆的含义
- android ANR产生原因和解决办法
- Android UI 优化——使用HierarchyViewer工具
- FreeMarker中文API手冊(完整)
- JavaScript算法(实例三)数组排序--冒泡排序 / sort() / reverse() / 比较函数
- 7-1 输出从1加到N的和 (9 分)
- 力扣225-用队列实现栈(C++,附思路及优化思路,代码)
- linux bash环境变量,linux-bash环境变量
- c++ new, operator new, placement new
- [BZOJ 4571][Scoi2016]美味(主席树)