关于研究SELECT * 是否会导致SQL查询效率变低的问题

news2024/11/23 18:29:29

引言

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

一、效率低的原因

先看一下最新《阿里java开发手册》中 MySQL 部分描述:【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。

其中要点说明:

  1. 增加查询分析器解析成本。
  2. 增减字段容易与xml中的resultMap配置不一致。
  3. 无用字段增加网络消耗,尤其是text等大字段。

开发手册中比较概括的提到了几点原因,接下来我们深入一些看看:

1. 不需要的列会增加数据传输时间和网络开销

  1. 用 "SELECT * " 会导致数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。

  2. 增大网络开销,SELECT * 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。如果DB和应用程序不在同一台机器,这种开销非常明显。

  3. 即使 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是二级目录下的三级目录。要使用某一目录,必须先使用其上级目录,一级目录除外。

比如:

where条件效果
where a=1 andC=1只使用了一级目录,c在三级目录,没有使用二级目录,那么三级目录就没法便用。
where a=1 andb=1只使用了一级目录、二级目录。

联合索引的优势

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 column1,column2,column3 from table where column1=1 and column2=2 and column3=3;

假设:假设每个条件可以筛选出 10% 的数据。

  • A. 如果只有单列索引,那么通过该索引能筛选出 1000W10%=100w 条数据,然后再回表从 100w 条数据中找到符合 col2=2 and col3= 3 的数据,然后再排序,再分页,以此类推(递归);

  • B. 如果是(col1,col2,col3)联合索引,通过三列索引筛选出 1000w10% 10% *10%=1w,效率提升可想而知!

4.索引是建的越多越好?

答案自然是否定的

  • 数据量小的表不需要建立索引,建立会增加额外的索引开销

  • 不经常引用的列不要建立索引,因为不常用,即使建立了索引也没有多大意义

  • 经常频繁更新的列不要建立索引,因为肯定会影响插入或更新的效率

  • 数据重复且分布平均的字段,因此他建立索引就没有太大的效果(例如性别字段,只有男女,不适合建立索引)

  • 数据变更需要维护索引,意味着索引越多维护成本越高。

  • 更多的索引也需要更多的存储空间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/719663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络_ 1.3 网络核心(数据交换_电路交换_多路复用)

计算机网络_数据交换_电路交换_多路复用 多路复用频分多路复用FDM时分多路复用TDM波分多路复用WDM码分多路复用CDM 多路复用 多路复用(Multiplexing),简称复用,是通信技术的基本概念。 链路/网络资源(如带宽&#x…

【动态规划算法】第四题:91.解码方法

💖作者:小树苗渴望变成参天大树 🎉作者宣言:认真写好每一篇博客 🎊作者gitee:gitee 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作…

一建建筑周超口袋书

第一部分 建筑工程技术1A414000 建筑工程材料[B-4,2021] 常见的高分子防水卷材有哪些?三元乙丙、聚氯乙烯、氯化聚乙烯、氯化聚乙烯-橡胶共混及三元丁橡胶防水卷材记忆技巧三单数年考试中,2011 年屋面女儿墙渗漏水处理,2015 年女儿墙防水识图找错&#…

element ui table 状态用switch展示

效果图如下 方法一:将图片封装成组件 1.:ImgswitchOpen.vue 2:页面引入组件 3:使用 方法二:引入图片 1:引入图片 2:在data中定义 3.使用

垂直领域大模型:从医疗ChatDoctor到金融BloombergGPT、法律ChatLaw/LawGPT_zh

第一部分 各种医疗类ChatGPT:或中英文数据微调LLaMA、或中文数据微调ChatGLM 1.1 基于LLaMA微调的中英文版ChatDoctor 1.1.1 ChatDoctor:通过self-instruct技术提示API的数据和医患对话数据集微调LLaMA Github上有一个基于LLaMA模型的医疗微调模型&am…

c++高性能264/265实时h5流媒体服务器前后端整体解决方案

c高性能264/265实时h5流媒体服务器前后端整体解决方案 1.效果展示 下图展示了前端播放效果。 播放1路264视频流,4路265视频流 CPU占用率10%(测试机器上运行着c服务端和其他工具程序) GPU0占用率17% 1.1 作者测试机器配置 处理器 11th Gen Intel Core™ i7-118…

如何确定适合网站的长尾关键词?

确定适合网站的长尾关键词,需要进行以下几个步骤: 1. 目标受众分析:首先,要确定网站的目标受众是谁。了解目标受众的特点和需求,可以帮助我们选择适合他们的长尾关键词。例如,如果目标受众是学生&#xff…

【Linux | Shell命令】Linux 环境变量

目录 一、概述二、什么是环境变量2.1 全局环境变量2.2 局部环境变量 三、设置用户自定义变量3.1 设置局部用户自定义变量3.2 设置全局环境变量3.3 删除环境变量 四、默认的 shell 环境变量五、5.1 设置 PATH 环境变量5.2 一、概述 Linux 系统中,很多程序和脚本通过环…

爱创科技携腾讯云拓展海内外药械数字溯源服务,“一物一码”全程可追踪

想象一下,当每个人从医院取药窗口或药房买到关乎自己生命健康的药品时,只需掏出手机打开微信,扫一扫药盒上的二维码,就可以看到药品真伪、出厂厂家、用药科普等信息,既带来一份用药的安心,也能清晰地看到医…

二进制、十进制相互转换

二进制转十进制: 1100 0000转为十进制的数值为:12864192 十进制转二进制: 列如:十进制数为202 1286432168421二进制11001010 解析: 202>128,第一个二进制数为:1 202-128>64&#xf…

服务器垃圾怎样清理?C盘垃圾如何清理?

好多人都在问电脑垃圾如何清理?服务器的垃圾清理是系统维护中必不可少的一项任务,而C盘垃圾的清理同样也是必须要做的任务之一。那么,如何一键清理服务器垃圾,C盘垃圾如何清理呢?今天,我会以服务器助手为例…

8、架构:服务端介绍

作为一个产品化的项目,就必然有服务端的支持,这次的项目我们依然使用与上一本小册一样的技术栈 NestJS作为产品的服务端开发语言。 服务端的内容对于常规的前端开发会比较难上手,因为除了服务端的开发语言之外,我们还需要安装各种…

如何查看docker File!!!!

1.如何查看dockerfile! 先docker images 查看所有的镜像,然后再一个目录下先创建一个脚本,把下面内容复制进去 #!/bin/bash export PATH$PATH if [ $# -eq 1 ];thendocker history --format {{.CreatedBy}} --no-trunctrue $1 |sed "s…

基于PyQt5的桌面图像调试仿真平台开发(6)去马赛克

系列文章目录 基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)…

c++ connect函数连接失败 解决方法

bool Connect() {//初始化网络WSADATA wsadata;WSAStartup(MAKEWORD(2, 2), &wsadata);if (0 ! WSAStartup(MAKEWORD(2, 2), &wsadata))return false;if (LOBYTE(wsadata.wVersion) ! 2 ||HIBYTE(wsadata.wVersion) ! 2) {printf("请求协议版本失败!\n");ret…

12.JavaWeb-Node.js+创建Vue项目

1.Node.js的概念 传统的Web服务器中,每个请求都会创建一个线程,这会导致线程数的增加,从而影响服务器的性能和扩展性,Ryan Dahl借助Chrome的V8引擎提供的能力实现了Node.js——可以在服务端运行的JavaScript(可以把Nod…

SQL-每日一题【197.上升的温度】

题目 表: Weather 编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 id 。 返回结果 不要求顺序 。 查询结果格式如下例。 示例 1: 解题思路 前置知识 交叉连接(CROSS JOIN) 即笛卡尔积&…

Vue Router 的params和query传参的使用和区别

//$router : 是路由操作对象,只写对象 //$route : 路由信息对象,只读对象//操作 路由跳转 this.$router.push({name:hello,params:{name:word,age:11} })//读取 路由参数接收 this.name this.$route.params.name; this.age this.$route.params.age; 1…

ADS笔记,时域和频域绘图

为防止遗忘,记录一下ADS的时间域和频谱图的绘制 在ADS中想得到电路的时域和频域图的话,可以用谐波平衡仿真HB或者选择一个准瞬态仿真控制器插入到原理图中来实现。 目录 方法一:谐波平衡仿真HB时域设置频域设置 方法二:准瞬态仿…

【Linux】git三板斧教程(免密提交配置)

git 什么是git?Linux下安装git基于git的一些商业网站介绍在gitee上创建仓库注册账号创建项目将仓库克隆到本地 git三板斧git三板斧第一招:git add三板斧第二招:git commit三板斧第三招:git push git免密码提交git log查看提交日志…