MySQL性能优化-Mysql索引篇(1)

什么是索引?

数据库中的索引,就好比一本书的目录,它可以帮我们快速进行特定值的定位与查找,从而加快数据查询的效率。索引就是帮助数据库管理系统高效获取数据的数据结构。如果我们不使用索引,就必须从第 1 条记录开始扫描,直到把所有的数据表都扫描完,才能找到想要的数据。

既然索引可以帮我们快速查找数据,是不是索引越多越好呢?
答案是否定的,索引不是万能的,一些情况下使用索引不仅不能提升效率,反而会让效率变低。

索引的价值是帮我们从海量数据中找到想要的数据,如果数据量少,那么是否使用索引对结果的影响并不大。下面列举下不需要使用索引的情况

在数据表中的数据行数比较少的情况下,比如不到 1000 行,是不需要创建索引的。
当数据重复度大,比如高于 10% 的时候,也不需要对这个字段使用索引。

对第二点做一个扩展说明:

如果是性别这个字段,就不需要对它创建索引。这是为什么呢?如果你想要在 100 万行数据中查找其中的 50 万行(比如性别为男的数据),一旦创建了索引,你需要先访问 50 万次索引,然后再访问 50 万次数据表,这样加起来的开销比不使用索引可能还要大。

光说不做假把式,下面对上述不应该使用索引的例子,进行实验证明。

实验 1:数据行数少的情况下,索引效率如何

比如我们有一张hero_tab,里面包含了一些英雄的基本属性,其中包含了英雄的名称。但是数据表中仅有69个英雄,可以说是数量非常少了。我们执行以下的sql语句查询英雄名称为刘备的记录。

SELECT id, name, hp_max, mp_max FROM heros_without_index WHERE name = '刘禅'

执行时间为0.072s

接下来我们为name字段建立唯一索引

ALTER TABLE `hero_tab` ADD UNIQUE INDEX `uniq_name`(`name`);

然后继续执行上面那条查询SQL

运行时间为0.080s

我们可以发现,创建了 name 字段索引的效率比没有创建索引时效率更低。在数据量不大的情况下,索引就发挥不出作用了。

实验 2:性别(男或女)字段真的不应该创建索引吗?

如果一个字段的取值少,比如性别这个字段,通常是不需要创建索引的。那么有没有特殊的情况呢?

比如一个女儿国中,总人口100w,男性只有10个,我们将性别信息记录在user_gender表(user_id、user_name、user_gender)中,0代表女生,1代表i男生

我们筛选出这个国家中男性的SQL如下:

SELECT * FROM user_gender WHERE user_gender = 1

执行时间:0.696s

一般来说,一条SQL的执行时间超过100ms就会被定义为慢SQL了,这个SQL的效率显然是不高的。

现在我们为这个user_gender字段加上索引,看看会不会对这条的执行效率有提升呢?

ATLER TABLE `user_gender` ADD INDEX `idx_user_gender`(`user_gender`);

我们再次运行之前那条SQL语句,发现执行时间为0.052s,显然执行效率提升了十几倍,已经不是一个慢SQL了。

索引的价值是帮你快速定位。如果想要定位的数据有很多,那么索引就失去了它的使用价值,比如通常情况下的性别字段。不过有时候,我们还要考虑这个字段中的数值分布的情况,在实验 2 中,性别字段的数值分布非常特殊,男性的比例非常少。我们不仅要看字段中的数值个数,还要根据数值的分布情况来考虑是否需要创建索引。

索引类型

从功能上进行分类,索引可以分为四大类:

普通索引是基础的索引,没有任何约束,主要用于提高查询效率。
唯一索引就是在普通索引的基础上增加了数据唯一性的约束,在一张数据表里可以有多个唯一索引。
主键索引在唯一索引的基础上增加了不为空的约束,也就是 NOT NULL+UNIQUE,一张表里最多只有一个主键索引。
全文索引用的不多,MySQL 自带的全文索引只支持英文。我们通常可以采用专门的全文搜索引擎,比如 ES(ElasticSearch) 和 Solr。

其实前三种索引(普通索引、唯一索引和主键索引)都是一类索引,只不过对数据的约束性逐渐提升。在一张数据表中只能有一个主键索引,这是由主键索引的物理实现方式决定的,因为数据存储在文件中只能按照一种顺序进行存储。但可以有多个普通索引或者多个唯一索引。

从物理实现的方式可以分为两种:

聚集索引
非聚集索引,非聚集索引也可以称为二级索引或者辅助索引

聚集索引:
聚集索引指表中数据行按索引的排序方式进行存储,对查找行很有效。只有当表包含聚集索引时,表内的数据行才会按找索引列的值在磁盘上进行物理排序和存储。每一个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。
聚集索引可以按照主键来排序存储数据,这样在查找行的时候非常有效。举个例子,如果是一本汉语字典,我们想要查找“数”这个字,直接在书中找汉语拼音的位置即可,也就是拼音“shu”。这样找到了索引的位置,在它后面就是我们想要找的数据行。

非聚集索引:
在数据库系统会有单独的存储空间存放非聚集索引,这些索引项是按照顺序存储的,但索引项指向的内容是随机存储的。也就是说系统会进行两次查找,第一次先找到索引,第二次找到索引对应的位置取出数据行。非聚集索引不会把索引指向的内容像聚集索引一样直接放到索引的后面,而是维护单独的索引表(只维护索引,不维护索引指向的数据),为数据检索提供方便。我们还以汉语字典为例,如果想要查找“数”字,那么按照部首查找的方式,先找到“数”字的偏旁部首,然后这个目录会告诉我们“数”字存放到第多少页,我们再去指定的页码找这个字。

聚集索引和非聚集索引使用上的区别:

聚集索引的叶子节点存储的就是我们的数据记录,非聚集索引的叶子节点存储的是数据位置。非聚集索引不会影响数据表的物理存储顺序。
一个表只能有一个聚集索引,因为只能有一种排序存储的方式,但可以有多个非聚集索引,也就是多个索引目录提供数据检索。
使用聚集索引的时候,数据的查询效率高,但如果对数据进行插入,删除,更新等操作,效率会比非聚集索引低。

实验 3:使用聚集索引和非聚集索引的查询效率

这里我们依然使用user_gender表作为实验对象,首先我们需要知道innodb存储引擎会默认用数据表的主键建立据聚集索引,索引user_gender表是建立了user_id这个字段的聚集索引的。

首先我们查询user_id为90001的用户信息,SQL如下

SELECT user_id, user_name, user_gender FROM user_gender WHERE user_id = 900001

执行时间为0.043s

刚才我们已经为user_name字段建立了唯一值索引,我们再来查询下用户名为’student_89001’的用户

SELECT user_id, user_name, user_gender FROM user_gender WHERE user_name = 'student_890001'

执行时间为0.050s

我们可以看出来,聚集索引的查询效率还是要比非聚集索引略高的。

我们还可以按照索引的字段个数进行划分:

单一索引:索引列为一列时为单一索引;
联合索引:多个列组合在一起创建的索引叫做联合索引。

创建联合索引时,我们需要注意创建时的顺序问题,因为联合索引 (x, y, z) 和 (z, y, x) 在使用的时候效率可能会存在差别。

这里需要说明的是联合索引存在最左匹配原则,也就是按照最左优先的方式进行索引的匹配。比如刚才举例的 (x, y, z),如果查询条件是 WHERE x=1 AND y=2 AND z=3,就可以匹配上联合索引;如果查询条件是 WHERE y=2,就无法匹配上联合索引。

实验 4:联合索引的最左原则

我们依然使用user_gender表作为实验的对象,首先我们删除之前的uniq_user_name索引,建立新的索引idx_user_id_user_name也就是user_id和user_name的联合索引,执行SQL如下:

ALTER TABLE DROP UNIQUE INDEX `uniq_user_name`, ADD INDEX `idx_user_id_user_name`(`user_id`,`user_name`);

我们依次执行以下两个SQL,根据user_id和user_name进行查询。

SELECT user_id, user_name, user_gender FROM user_gender WHERE user_id = 900001 AND user_name = 'student_890001'

执行时间0.046s

SELECT user_id, user_name, user_gender FROM user_gender WHERE user_name = 'student_890001'

执行时间:0.943s

我们可以看到,用两个条件进行查询,查询效率差别是非常大的,原因在于:
当我们使用了联合索引 (user_id, user_name) 的时候,在 WHERE 子句中对联合索引中的字段 user_id 和 user_name 进行条件查询,或者只对 user_id 进行查询,效率基本上是一样的。当我们对 user_name 进行条件查询时,效率就会降低很多,这是因为根据联合索引的最左原则,user_id 在 user_name 的左侧,如果没有使用 user_id,而是直接使用 user_name 进行条件查询,联合索引就会失效。

如果你不相信的话,可以使用explain语句看看两条语句执行时,索引使用情况。

总结

在这里插入图片描述

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

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

相关文章

什么台灯护眼效果好?一文搞懂如何正确挑选护眼台灯

现在的孩子学习状态可以用四个字来形容,“学业繁重”,不少孩子从上小学开始,晚上完成功课到八九点都是在正常不过的事情了,因此室内的光线环境是非常重要的,直接影响了视力健康尤其是书桌上的那一盏台灯,有…

012 Linux_线程控制

前言 本文将会向你介绍线程控制(创建(请见上文),终止,等待,分离) 线程控制 线程终止 pthread_t pthread_self(void); 获取线程自身的ID 如果需要只终止某个线程而不终止整个进程,可以有三种…

SparkShop开源可商用,匹配小程序H5和PC端带分销功能!

SparkShop(星火商城)B2C商城是基于thinkphp6 elementui的开源免费可商用的高性能商城系统;包含小程序商城、H5商城、公众号商城、PC商城、App,支持页面diy、秒杀、优惠券、积分、分销、会员等级。营销功能采用插件化的方式方便扩展、二次开发 源码下载…

表单验证、属性绑定(一个属性根据另一个属性有无进行操作)

表单验证 一个属性根据另一个属性有无进行操作(属性绑定) 1、问题描述 ​ 需求:表单里面后两个属性需要根据前面一个属性进行有无判断。如果前面属性没有输入值,则不需要进行操作;如果前面属性有输入值,则…

Docker Swarm全解析:实现微服务高可用与故障转移的秘密武器

🐇明明跟你说过:个人主页 🏅个人专栏:《Docker入门到精通》 《k8s入门到实战》🏅 🔖行路有良友,便是天堂🔖 目录 一、基本概念和介绍 1、Docker Swarm 是什么,它与 …

Rabbitmq消息丢失-消费者消息丢失(二)

说明:消费端在处理消息的过程中出现异常,例如:业务逻辑异常,或者消费者被停机,或者网络断开连接等,以上等情况使消息没有得到正确恰当的处理,也会使消息丢失。 分析:分析就是说明中…

【MATLAB第97期】基于MATLAB的贝叶斯Bayes算法优化BiGRU双向门控循环单元的多输入单输出回归预测模型,含GRU与BiGRU多层结构优化选择

【MATLAB第97期】基于MATLAB的贝叶斯Bayes算法优化BiGRU双向门控循环单元的多输入单输出回归预测模型,含GRU与BiGRU结构层数优化 前言 前面在【MATLAB第10期】讲解了基于贝叶斯Bayes算法优化LSTM长短期记忆网络的多输入单输出回归预测模型。 本次模型难点包括&am…

Ps:图案图章工具

图案图章工具 Pattern Stamp Tool可将各种预设图案或自定义的图案,通过画笔涂抹的方式填充到图像中。 快捷键:S 图案图章工具提供了一种快速、灵活的方式来为图像局部添加纹理和装饰。 这个工具类似于仿制图章工具,但区别在于,它使…

初阶数据结构:二叉树(补充扩展)

目录 1. 堆排序1.1补充:建堆的时间复杂度1.2 堆排序:升序与降序 2. TopK问题3. 二叉树的链式结构及其遍历方式3.1 二叉树的链式结构3.2 二叉树的前序遍历2.2 二叉树的中序遍历2.3 后序遍历2.4 层序遍历 4. 二叉树OJ练习4.1 单值二叉树4.2 判断两棵二叉树…

three.js如何实现简易3D机房?(一)基础准备-上

目录 一、tips 二、功能说明 1.模型初始化 2.功能交互 三、初始化准备 1.目录结构 2.创建三要素 3.创建轨道控制器 4.初始化灯光 5.适配 6.循环渲染 一、tips 1.three.js入门的相关基础性知识就不在此过多赘述了,可以自行提前了解 three.js docs&…

PyTorch深度学习实战(38)——StyleGAN详解与实现

PyTorch深度学习实战(38)——StyleGAN详解与实现 0. 前言1. StyleGAN1.1 模型介绍1.2 模型策略分析 2. 实现 StyleGAN2.1 生成图像2.2 风格迁移 小结系列链接 0. 前言 StyleGAN (Style-Generative Adversarial Networks) 是生成对抗网络 (Generative Ad…

基于Docker部署本地ChatGPT环境

基于Docker部署本地ChatGPT环境 一、拉取镜像 docker pull pengzhile/pandora二、运行镜像 docker run -e PANDORA_CLOUDcloud -e PANDORA_SERVER0.0.0.0:8899 -p 8899:8899 -d pengzhile/pandora三、查看容器是否启动成功 docker ps四、登录 http://IP:8899 这里有两种方…

原始手写helloworld并打jar包允许

1.创建文件夹test统一在其中操作 2.创建hello.java文件 【hello.txt改属性为hello.java】并在里面添加代码 public class hello {public static void main(String[] args) {System.out.println("hello world");} } 注意:类名与文件名一致 然后运行…

使用AI创建令人惊叹的3D模型

老子云平台《《《《《 使内容创作者能够在一分钟内毫不费力地将文本和图像转换为引人入胜的 3D 资产。 文本转 3D 我们的文本转 3D 工具使创作者(包括那些没有 3D 经验的创作者)能够使用文本输入在短短一分钟内生成 3D 模型。 一句话生成3D模型 老子…

FPGA-VGA成像原理与时序

什么是VGA: VGA, Video Graphics Array。即视频图形阵列,具有分辨率高、显示速率快、颜色丰富等优点。VGA接口不但是CRT显示设备的标准接口,同样也是LCD液晶显示设备的标准接口,具有广泛的应用范围。在FGPA中,常广泛用于图像处理等领域。 VGA 显示器成像原理 在 VGA 标准刚兴…

Material UI 5 学习02-其它按钮组件

Material UI 5 学习02-其它按钮组件 一、IconButton按钮二、 ButtonGroup按钮组1、最基本的实例2、垂直按钮组 一、IconButton按钮 图标按钮通常适用于切换按钮&#xff0c;允许选择或选择单个选项 取消选择&#xff0c;例如在项目中添加或删除星号。 <IconButton aria-lab…

docker pull 拉取失败,设置docker国内镜像

遇到的问题 最近在拉取nginx时&#xff0c;显示如下错误&#xff1a;Error response from daemon: Get “https://registry-1.docker.io/v2/”: net/http: request canceled (Client.Timeout exceeded while awaiting headers)。 这个的问题是拉取镜像超时&#xff0c;通过检索…

RISC-V特权架构 - 机器模式下的异常处理

RISC-V特权架构 - 机器模式下的异常处理 1 进入异常1.1 从mtvec 定义的PC 地址开始执行1.2 更新CSR 寄存器mcause1.3 更新CSR 寄存器mepc1.4 更新CSR 寄存器mtval1.5 更新CSR 寄存器mstatus 2 退出异常2.1 从mepc 定义的PC 地址开始执行2.2 更新CSR 寄存器mstatus 3 异常服务程…

Docker Protainer可视化平台,忘记登录密码,重置密码。

由于好久没有登录portainer系统&#xff0c;导致忘记了登录密码&#xff0c;试了好多常用的密码都不对&#xff0c;无奈只能重置密码。 一、停止protainer 容器 查看容器ID和COMMAND 用于停止容器 docker ps -a停止容器 docker stop portainer二、查找volume data 宿主机所在…

脉冲电阻器负载、功率和电压降额,选型分析

本文讨论了关键的电阻脉冲负载、功率和电压降额参数&#xff0c;这些参数对于正确选择指南和可靠运行这些无源元件非常重要。 EAK脉冲负载 在许多应用中&#xff0c;电阻器将承受脉冲负载。我们区分周期性/重复性负载和脉冲序列;一方面&#xff0c;脉冲以一定频率重复&#xff…