为什么不能用select *
面试官:“小陈,说一下你常用的SQL优化方式吧。”
陈小哈:“那很多啊,比如不要用SELECT *,查询效率低。巴拉巴拉...”面试官:“为什么不要用SELECT * ?它在哪些情况下效率低呢?”
陈小哈:“SELECT * 它好像比写指定列名多一次全表查询吧,还多查了一些无用的字段。”面试官:“嗯...”
陈小哈:“emmm~ 没了”陈小哈:“....??(几个意思)”
面试官:“嗯...好,那你还有什么要问我的么?”
陈小哈:“我问你个锤子,把老子简历还我!”
无论在工作还是面试中,关于SQL中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但普遍理解还是在很浅的层面,并没有多少人去追根究底,探究其原理。
废话不多说,本文带你深入了解一下"SELECT * "效率低的原因及场景。更多 SQL 相关的干货可以关注微信公众号「Java后端」回复「666」下载 Java技术栈手册。
本文很干!请自备茶水,没时间看记得先收藏 - 来自一位被技术经理毒打多年的程序员的忠告
目录
一、效率低的原因
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 操作
3. 失去MySQL优化器“覆盖索引”策略优化的可能性
select *
,获取了不需要的数据,则首先通过辅助索引过滤数据,然后再通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。二、索引知识延申
联合索引 (a,b,c)
联合索引的优势
1) 减少开销
2)覆盖索引
SELECT a,b,c from table where a='xx' and b = 'xx';
3)效率高
select col1,col2,col3 from table where col1=1 and col2=2 and col3=3;
A. 如果只有单列索引,那么通过该索引能筛选出 1000W10%=100w 条数据,然后再回表从 100w 条数据中找到符合 col2=2 and col3= 3 的数据,然后再排序,再分页,以此类推(递归); B. 如果是(col1,col2,col3)联合索引,通过三列索引筛选出 1000w10% 10% *10%=1w,效率提升可想而知!
索引是建的越多越好吗
数据量小的表不需要建立索引,建立会增加额外的索引开销
不经常引用的列不要建立索引,因为不常用,即使建立了索引也没有多大意义
经常频繁更新的列不要建立索引,因为肯定会影响插入或更新的效率
数据重复且分布平均的字段,因此他建立索引就没有太大的效果(例如性别字段,只有男女,不适合建立索引)
数据变更需要维护索引,意味着索引越多维护成本越高。
更多的索引也需要更多的存储空间