MySQL的优化利器:索引条件下推,千万数据下性能提升273%

MySQL的优化利器:索引条件下推,千万数据下性能提升273%🚀

前言

上个阶段,我们聊过MySQL中字段类型的选择,感叹不同类型在千万数据下的性能差异

时间类型:MySQL字段的时间类型该如何选择?千万数据下性能提升10%~30%🚀

字符类型:MySQL字段的字符类型该如何选择?千万数据下varchar和char性能竟然相差30%🚀

新的阶段我们来聊聊MySQL中索引的优化措施,本篇文章主要聊聊MySQL中的索引条件下推

同学们可以带着这些问题来看本篇文章:

  1. MySQL中多查询条件的语句是如何执行的?server层与存储引擎层如何交互?
  2. 聚簇索引和二级索引存储内容的区别?
  3. 什么是回表?回表有哪些开销?如何避免回表?
  4. 什么是索引条件下推?
  5. 什么时候可以用上索引条件下推?
  6. 索引条件下推能解决什么问题?
  7. 千万数据量下索引条件下推能提升多少性能?

server层与存储引擎层

MySQL服务端可以分为server层与存储引擎层,存储引擎层主要存储记录,可以用不同的存储引擎实现(innodb,myisam)

server层有不同的组件处理不同的功能,比如:接收客户端请求(连接器)、检查SQL语法(分析器)、判断缓存命中(查询缓存8.0移除)、优化SQL和选择索引生成执行计划(优化器)、调用存储引擎获取记录(执行器)

image.png

server层与存储引擎层的交互

以学生表为例

CREATE TABLE `student` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `age` smallint(6) DEFAULT NULL COMMENT '年龄',
  `student_name` varchar(20) DEFAULT NULL COMMENT '名称',
  `info` varchar(30) DEFAULT NULL COMMENT '信息',
  PRIMARY KEY (`id`),
  KEY `idx_age_name` (`age`,`student_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

聚簇(主键)索引以主键id有序存储整个记录的值

image.png

二级索引只存储规定的索引列和主键,并且以索引列、主键值的先后顺序有序

二级索引为(age,student_name)联合索引时整体上age有序,当age相等时,student_name有序,当student_name相等时,主键有序

image.png

当发生多条件查询时(where 有多个条件),执行器从存储引擎层获取完数据还需要在server层过滤其他查询条件

比如select * from student where age = 18 and student_name like 'c%'; (查询学生表中年龄为18,名称为c开头的学生)

存在(age,student_name)的联合索引,优化器会认为联合索引是最优的,于是生成使用(age,student_name)联合索引的执行计划,执行器根据执行计划调用存储引擎层

在存储引擎层会根据age = 18进行匹配,当满足此条件时,先回表查询聚簇索引

什么是回表?

二级索引只存储需要的列和主键,聚簇(主键)索引存储所有数据

由于我们使用的索引没有存储查询列表需要的列,于是需要去聚簇(主键)索引中再次查询获取其他列的值

image.png

在这个过程中主键值可能是乱序的,因此回表查询聚簇索引时,会出现随机IO(开销大)

server层与存储引擎层交互的单位是记录

image.png

  1. server层优化器根据索引生成执行计划,执行器调用存储引擎层
  2. 存储引擎层在联合索引中寻找满足 age=18的记录
  3. 每次找到记录回表查询聚簇索引获取其他列的值
  4. 然后返回给server层进行where过滤
  5. 2-4实际是一个循环,直到找到第一条不满足条件的记录

在这个流程中会发现一个问题:student_name like 'c%'可以在存储引擎层的联合索引中就判断,并不需要回表查询聚簇索引后返回server层判断

索引条件下推 Index Condition Push

索引条件下推英文名:Index Condition Push

将判断where条件从server层下推到存储引擎层,也就是说存储引擎层也会判断查询其他条件

比如age=18 and student_name like 'c%',在回表前还需要判断student_name是否满足

图中第一条和第三条记录不满足student_name like 'c%'因此不回表直接跳过

image.png

索引条件下推ICP 防止明明可以在存储引擎层判断,但还回表查询后拿到server层判断,减少回表次数

image.png

加入ICP后的执行步骤:

  1. server层优化器根据索引生成执行计划,执行器调用存储引擎层
  2. 存储引擎层在索引上查找满足age=18的记录
  3. 找到满足条件的记录后,根据索引上现有列判断其他查询条件,不满足则跳过该记录
  4. 满足则回表查询聚簇索引其他列的值
  5. 获取需要查询的值后,返回server层进行where过滤
  6. 2-5步骤为循环执行,直到找到第一条不满足条件的记录

测试

开启函数创建

#开启函数创建
set global log_bin_trust_function_creators=1;

#ON表示已开启
show variables like 'log_bin_trust%';

定义随机生成字符串函数

#分割符从;改为$$
delimiter $$
#函数名ran_string 需要一个参数int类型 返回类型varchar(255)
create function ran_string(n int) returns varchar(255)
begin
#声明变量chars_str默认'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
#声明变量return_str默认''
declare return_str varchar(255) default '';
#声明变量i默认0
declare i int default 0;
#循环条件 i<n
while i < n do
set return_str = concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i=i+1;
end while;
return return_str;
end $$

定义范围生成整形函数

#生成范围生成整形的函数
delimiter $$
create function range_nums(min_num int(10),max_num int(10)) returns int(5)
begin
declare i int default 0;
set i = FLOOR(RAND() * (max_num - min_num + 1)) + min_num;
return i;
end $$

定义插入函数

#插入 从参数start开始 插入max_num条数据
delimiter $$ 
create procedure insert_students_tests(in start int(10),in max_num int(10))
begin
declare i int default start;
set autocommit = 0;
repeat
set i = i+1;
#SQL 语句
insert into student(student_name,age,info) 
values (ran_string(10),range_nums(0,100),ran_string(20));
until i=max_num
end repeat;
commit;
end $$

执行

#执行插入函数
delimiter ;
call insert_students_tests(0,19000000);

我测试的数据量是1900百万

记得建立索引

alter table student add index idx_age_name(age,student_name);

索引条件下推默认情况是开启的,SQL_NO_CACHE是不使用缓存(MySQL5.7 版本还有缓存)

select SQL_NO_CACHE * from student where age = 18 and student_name like 'c%'
> OK
> 时间: 1.339s

那如何判断是否使用到索引条件下推呢?

我们使用explain查看执行计划,当附加信息中存在Using index condition说明使用索引条件下推

image.png

那如何关闭索引条件下推呢?

这里我们使用会话级别的关闭

SET optimizer_switch = 'index_condition_pushdown=off';

关闭后,再查看执行计划发现附加信息中不再有Using index condition

image.png

select SQL_NO_CACHE * from student where age = 18 and student_name like 'c%'
> OK
> 时间: 5.039s

(5.039 - 1.339) / 1.339 = 276% ,使用索引条件下推提升的性能竟为 276%

经过前面的分析,索引条件下推是通过减少回表的次数从而优化性能,因此这里提升的性能实际上节省不必要的回表开销

在查询大数据量情况下,回表不仅要多查聚簇索引,还可能导致随机IO(增加与磁盘的交互)

虽然可以通过索引条件下推优化减少回表次数,但还是会有符合条件的记录需要回表

那有没有什么办法可以尽量避免回表或让回表的开销变小呢?

如果在二级索引上就已经得到需要查询的列(比如查询age,student_name,id),那么就不用回表

那如果还是要去聚簇索引查询其他列,该如何降低回表的开销呢?

这个问题留着下一章讨论,如果你想到什么方案也可以在评论区交流喔~

总结

MySQL服务端分为server层与存储引擎层,存储引擎层可以通过不同的实现(innodb,myisam)存储记录

server层拥有分工明确的不同组件:连接器(管理请求连接)、分析器(处理SQL语法、词性分析)、优化器(优化SQL,根据不同索引生成执行计划)、执行器(根据执行计划调用存储引擎获取记录)

server层与存储引擎层以记录为单位进行交互,server层执行器根据执行计划调用存储引擎层获取记录

二级索引存储索引列和主键的值,并以索引列、主键进行排序,有多个索引列时,前一个索引列相等时当前索引列才有序;聚簇索引存储整条记录的值,并以主键有序

当使用二级索引并且二级索引上的列不满足查询条件时,需要回表查询聚簇索引获取其他列的值;回表查询聚簇索引时主键值无序可能导致随机IO

索引条件下推在多查询条件的情况下,在存储引擎层多判断一次where其他查询条件,利用二级索引上的其他列判断记录是否满足其他查询条件,如果不满足则不用回表,减少回表次数

查询数据量大的情况下,回表的开销非常大,只有当二级索引存在的列满足查询需要的列时才不会回表,回表产生的随机IO要通过其他手段优化

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 由点到线,由线到面,构建MySQL知识体系,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Go版]算法通关村第十八关青铜——透析回溯的模版

目录 认识回溯思想回溯的代码框架从 N 叉树说起有的问题暴力搜索也不行回溯 递归 局部枚举 放下前任Go代码【LeetCode-77. 组合】回溯热身-再论二叉树的路径问题题目&#xff1a;二叉树的所有路径Go 代码 题目&#xff1a;路径总和 IIGo 代码 回溯是最重要的算法思想之一&am…

【Jenkins 安装】

一&#xff1a;安装文件夹准备 在/home/admin 界面下新建三个文件夹&#xff0c;用来安装tomcat、maven 1.打开&#xff0c;/home/admin目录 cd /home/admin 2.新建三个文件夹 mkdir tomcat mkdir maven 二&#xff1a;安装tomcat 1.打开tomcat目录进行tomcat的安装 访问:h…

LSKA(大可分离核注意力):重新思考CNN大核注意力设计

文章目录 摘要1、简介2、相关工作3、方法4、实验5、消融研究6、与最先进方法的比较7、ViTs和CNNs的鲁棒性评估基准比较8、结论 摘要 https://arxiv.org/pdf/2309.01439.pdf 大型可分离核注意力&#xff08;LSKA&#xff09;模块的视觉注意力网络&#xff08;VAN&#xff09;已…

SpringDoc API文档工具集成SpringBoot - Swagger3

1、引言 之前在Spring Boot项目中一直使用的是SpringFox提供的Swagger库&#xff0c;发现已经超过3年没出新版本了&#xff01;SpringDoc是一款可以结合Spring Boot使用的API文档生成工具&#xff0c;基于OpenAPI 3&#xff0c;是一款更好用的Swagger库&#xff01;值得一提的是…

高速下载b站视频的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

JAVA 链式编程和建造者模式的使用(lombok的使用)

0.说明 0.1 链式编程 链式编程的原理是返回一个this对象&#xff0c;也就是返回对象本身&#xff0c;从而达到链式效果。这样可以减少一些代码量&#xff0c;是java8新增的内容。 此处主要介绍在新建对象使用链式编程更加方便的创建对象。链式编程的一些常见用法可以看这个&a…

C++笔记之初始化二维矩阵的方法

C笔记之初始化二维矩阵的方法 —— 2023年5月20日 上海 code review! 文章目录 C笔记之初始化二维矩阵的方法一.常见方法1. 使用数组2. 使用向量3. 使用数组的动态分配4. 使用嵌套的 std::vector 并使用resize方法5. 初始化固定大小的 std::array 二.C中使用vector初始化二维矩…

CSS3属性详解(一)文本 盒模型中的 box-ssize 属性 处理兼容性问题:私有前缀 边框 背景属性 渐变 前端开发入门笔记(七)

CSS3是用于为HTML文档添加样式和布局的最新版本的层叠样式表&#xff08;Cascading Style Sheets&#xff09;。下面是一些常用的CSS3属性及其详细解释&#xff1a; border-radius&#xff1a;设置元素的边框圆角的半径。可以使用四个值设置四个不同的圆角半径&#xff0c;也可…

基于Java的新闻发布管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

华为云HECS云服务器docker环境下安装nacos

华为云HECS云服务器&#xff0c;安装docker环境&#xff0c;查看如下文章。 华为云HECS安装docker-CSDN博客 一、拉取镜像 docker pull nacos/nacos-server二、宿主机创建挂载目录 执行如下命令&#xff1a; mkdir -p /usr/local/nacos/logs mkdir -p /usr/local/nacos/con…

基于指数分布优化的BP神经网络(分类应用) - 附代码

基于指数分布优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于指数分布优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.指数分布优化BP神经网络3.1 BP神经网络参数设置3.2 指数分布算法应用 4.测试结果…

模型保存和加载

1、sklearn模型的保存和加载API from sklearn.externals import joblib 保存&#xff1a;joblib.dump(rf, ‘test.pkl’)加载&#xff1a;estimator joblib.load(‘test.pkl’) 2、决策树的模型保存加载案例 保存&#xff1a; import joblib from sklearn.model_selectio…

OpenCV #以图搜图:感知哈希算法(Perceptual hash algorithm)的原理与实验

1. 介绍 感知哈希算法&#xff08;Perceptual Hash Algorithm&#xff0c;简称pHash&#xff09; 是哈希算法的一种&#xff0c;主要用来做相似图片的搜索工作。 2. 原理 感知哈希算法&#xff08;pHash&#xff09;首先将原图像缩小成一个固定大小的像素图像&#xff0c;然后…

【模式识别】贝叶斯决策模型理论总结

贝叶斯决策模型理论 一、引言二、贝叶斯定理三、先验概率和后验概率3.1 先验概率3.2 后验概率 四、最大后验准则五、最小错误率六、最小化风险七、最小最大决策八、贝叶斯决策建模参考 一、引言 在概率计算中&#xff0c;我们常常遇到这样的一类问题&#xff0c;某事件的发生可…

MobileNetV3

相对重量级网络而言&#xff0c;轻量级网络的特点是参数少、计算量小、推理时间短。更适用于存储空间和功耗受限的场景&#xff0c;例如移动端嵌入式设备等边缘计算设备。因此轻量级网络受到了广泛的关注&#xff0c;其中MobileNet可谓是其中的佼佼者。MobileNetV3经过了V1和V2…

iOS 配置通用链接(Universal Link)服务端和开发者后台都配置好了,还是跳转不到App

目录 一、什么是 Universal Link&#xff1f; 1.背景介绍 2.特点 3.运行机制原理&流程图 二、配置教程 1.第一步&#xff1a;开启 Associated Domains 服务 1.1 开通 Associated Domains 2.第二步&#xff1a;服务器配置 apple-app-site-association&#xff08;AAS…

RISC-V架构——中断处理和中断控制器介绍

1、ARM架构中断机制介绍 本文不是从零开始讲解中断&#xff0c;对于中断的基本知识不再赘述&#xff0c;对中断不是很了解可以先学习ARM中断的文章。参考博客&#xff1a;《ARM架构的外部中断介绍(S5PV210芯片)》&#xff1b; 2、RIAC_V架构的中断控制器架构 &#xff08;1&…

Qt之自定义事件QEvent

在Qt中,自定义事件的步骤大概如下: 1.创建自定义事件,自定义事件需要继承QEvent 2.使用QEvent::registerEventType()注册自定义事件类型,事件的类型需要在 QEvent::User 和 QEvent::MaxUser 范围之间,在QEvent::User之前是预留给系统的事件 3.使用sendEvent() 和 postEv…

【软件安装】Linux系统中安装MySQL数据库服务

这篇文章&#xff0c;主要介绍如何在Linux系统中安装MySQL数据库服务。 目录 一、Linux安装MySQL 1.1、下载MySQL安装包 1.2、解压MySQL安装包 1.3、更改存放目录 1.4、创建用户组和用户 1.5、创建数据目录data 1.6、创建my.cnf配置文件 1.7、初始化数据库 1.8、添加m…

C# 基于腾讯云人脸核身和百度云证件识别技术相结合的 API 实现

目录 腾讯云人脸核身技术 Craneoffice.net 采用的识别方式 1、活体人脸核身(权威库)&#xff1a; 2、活体人脸比对&#xff1a; 3、照片人脸核身(权威库)&#xff1a; 调用成本 百度云身份证识别 调用成本 相关结合点 核心代码 实现调用人脸核身API的示例 实现调用身…