SELECT * 效率低原理解析

 更新时间:2023年02月02日 08:48:24   作者:博学谷  
这篇文章主要为大家介绍了SELECT * 效率低原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

效率低的原因

无论在工作还是面试中,关于SQL中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但普遍理解还是在很浅的层面,并没有多少人去追根究底,探究其原理。

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

【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。说明:

  • 增加查询分析器解析成本。
  • 增减字段容易与 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. 如果只有单列索引,那么通过该索引能筛选出 1000W 10%=100w 条数据,然后再回表从 100w 条数据中找到符合 col2=2 and col3= 3 的数据,然后再排序,再分页,以此类推(递归);
  • B. 如果是(col1,col2,col3)联合索引,通过三列索引筛选出 1000w 10% 10% *10%=1w,效率提升可想而知!

4)索引是建的越多越好吗

答案自然是否定的

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

以上就是SELECT * 效率低原理解析的详细内容,更多关于SELECT * 效率低原理的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL执行状态的查看与分析

    MySQL执行状态的查看与分析

    今天小编就为大家分享一篇关于MySQL执行状态的查看与分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • MySQL 数据库跨操作系统的最快迁移方法

    MySQL 数据库跨操作系统的最快迁移方法

    原始的是Windows 2003下的32位的MySQL数据库, 新的服务器是Sun的64位的小型机,64位的MySQL数据库。
    2009-02-02
  • mysql如何判断同一字段是否有重复数据

    mysql如何判断同一字段是否有重复数据

    这篇文章主要介绍了mysql如何判断同一字段是否有重复数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • 快速解决mysql深分页问题

    快速解决mysql深分页问题

    这篇文章主要介绍了优雅地解决mysql深分页问题,本文将会讨论当mysql表大数据量的情况,如何优化深分页问题,并附上最近的优化慢sql问题的案例伪代码,需要的朋友可以参考下
    2022-07-07
  • 解决Mysql数据库插入数据出现问号(?)的解决办法

    解决Mysql数据库插入数据出现问号(?)的解决办法

    这篇文章主要介绍了解决Mysql数据库插入数据出现问号(?)的解决办法的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • Ubuntu下启动、停止、重启MySQL,查看错误日志命令大全

    Ubuntu下启动、停止、重启MySQL,查看错误日志命令大全

    这篇文章主要介绍了Ubuntu下启动、停止、重启MySQL,查看错误日志命令大全,需要的朋友可以参考下
    2014-06-06
  • Sphinx/MySQL 协议支持与SphinxQL应用实例

    Sphinx/MySQL 协议支持与SphinxQL应用实例

    Sphinx/MySQL 协议支持与SphinxQL应用例子,供大家学习参考
    2013-02-02
  • 解决MySQL数据库链接超时报1129错误问题

    解决MySQL数据库链接超时报1129错误问题

    MySQL 为了数据库的安全性默认在链接中断或者错误时记录错误链接的ip 等信息(host_cache),有点像系统的错误日志的一种机制,这篇文章主要介绍了MySQL数据库链接超时报1129错误解决办法,需要的朋友可以参考下
    2022-10-10
  • MySQL中预处理语句prepare、execute与deallocate的使用教程

    MySQL中预处理语句prepare、execute与deallocate的使用教程

    这篇文章主要介绍了MySQL中预处理语句prepare、execute与deallocate的使用教程,文中通过示例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-08-08
  • MySQL单表查询实例详解

    MySQL单表查询实例详解

    这篇文章主要给大家介绍了关于MySQL单表查询的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09

最新评论