MySQL索引篇

news2025/2/22 17:15:11

文章目录

      • 说明:
      • 索引篇
          • 一、索引常见面试题
            • 按数据结构
            • 按物理存储分类
            • 按字段特性分类
            • 按字段个数分类
            • 索引缺点:
            • 什么时候适用索引?
            • 什么时候不需要创建索引?
            • 常见优化索引的方法:
            • 发生索引失效的情况:
          • 二、从数据页角度看B+树
          • 三、为什么 MySQL 采用 B+ 树作为索引?
          • 四、单表不要超过2000W行,一般靠谱
          • 五、索引失效有哪些?
          • 六、MySQL 使用 like “%x“,索引一定会失效吗?
          • 七、 count(*) 和 count(1) 有什么区别?哪个性能最好?

说明:

此类文章是为小林coding的图解MySQL,所简写,目的在于大家更快抓到小林文章的重点
本文全部由我简化,但是其中有部分引用小林的文章内容
希望大家掌握精髓,构建知识体系和知识框架

索引篇

一、索引常见面试题
  • 索引底层使用了什么数据结构和算法?
  • 为什么 MySQL InnoDB 选择 B+tree 作为索引的数据结构?
  • 什么时候适用索引?
  • 什么时候不需要创建索引?
  • 什么情况下索引会失效?
  • 有什么优化索引的方法?

索引分类

按数据结构
  • 按「数据结构」分类:B+tree索引、Hash索引、Full-text索引
  • 按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)
  • 按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引
  • 按「字段个数」分类:单列索引、联合索引

InnoDB存储引擎,B+Tree索引类型,优势:查询效率高,查询一个数据的磁盘I/O依然维持在3-4次

1、B+Tree vs B Tree

B+Tree 的单个节点的数据量更小(只在叶子节点存储数据,而…),在相同的磁盘 I/O 次数下,就能查询更多的节点。
B+Tree 叶子节点采用的是双链表连接,适合 MySQL 中常见的基于范围的顺序查找

2、B+Tree vs 二叉树

搜索复杂度为O(logdN)(节点允许的最大子节点个数为 d 个),也就是说一次数据查询操作只需要做 3~4 次的磁盘 I/O 操作就能查询到目标数据,
所经历的磁盘I/O次数

3、B+Tree vs Hash

Hash 在做等值查询的时候效率贼快,搜索复杂度为 O(1),但不适合做范围查询

  • 主键索引的 B+Tree 的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;

  • 二级索引的 B+Tree 的叶子节点存放的是主键值,而不是实际数据。

    按物理存储分类

**覆盖索引:**在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引
**回表:**如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,就能查询到数据了,这个过程就是回表

按字段特性分类
PRIMARY KEY (index_column_1) USING BTREE # 主键索引
UNIQUE KEY(index_column_1,index_column_2,...)  # 唯一索引
# 建表后,如果要创建唯一索引
CREATE UNIQUE INDEX index_name
ON table_name(index_column_1,index_column_2,...); 
# 普通索引
INDEX(index_column_1,index_column_2,...)  
# 前缀索引
column_list,
INDEX(column_name(length))
# 建表后,如果要创建前缀索引
CREATE INDEX index_name
ON table_name(column_name(length)); 
按字段个数分类
  • 建立在单列上的索引称为单列索引,比如主键索引;
  • 建立在多列上的索引称为联合索引;

使用联合索引时,存在最左匹配原则
CREATE INDEX index_product_no_name ON product(product_no, name);

索引缺点:
  • 需要占用物理空间,数量越大,占用空间越大;
  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增大;
  • 降低表的增删改的效率,因为每次增删改索引,B+ 树为了维护索引有序性,都需要进行动态维护。
什么时候适用索引?
  • 字段有唯一性限制的;
  • 经常用于 WHERE 查询条件的字段,这样能够提高整个表的查询速度,如果查询条件不是一个字段,可以建立联合索引。
  • 经常用于 GROUP BYORDER BY 的字段,这样在查询的时候就不需要再去做一次排序了,因为我们都已经知道了建立索引之后在 B+Tree 中的记录都是排序好的
什么时候不需要创建索引?
  • WHERE 条件,GROUP BYORDER BY 里用不到的字段,索引的价值是快速定位,如果起不到定位的字段通常是不需要创建索引的,因为索引是会占用物理空间的。
  • 字段中存在大量重复数据,比如性别字段,只有男女
  • 表数据太少的时候,不需要创建索引;
  • 经常更新的字段不用创建索引,比如不要对电商项目的用户余额建立索引,因为索引字段频繁修改,由于要维护 B+Tree的有序性,那么就需要频繁的重建索引,这个过程是会影响数据库性能的。
常见优化索引的方法:
  • 前缀索引优化;
    为了减小索引字段大小
    order by 就无法使用前缀索引;
    无法把前缀索引用作覆盖索引;
  • 覆盖索引优化;
    避免回表的操作
    假设我们只需要查询商品的名称、价格
    建立一个联合索引,即「商品ID、名称、价格」作为一个联合索引
  • 主键索引最好是自增的;
    如果我们使用自增主键,每次插入一条新记录,都是追加操作,不需要重新移动数据
  • 防止索引失效;
    索引最好设置为 NOT NULL,否则,优化器在做索引选择的时候更加复杂,更加难以优化,比如进行索引统计时,count 会省略值为NULL 的行
    没意义的值,但是它会占用物理空间
发生索引失效的情况:
  • 使用左或者左右模糊匹配的时候,也就是 like %xx 或者 like %xx%这两种方式都会造成索引失效;
  • 在查询条件中对索引列做了计算、函数、类型转换操作
  • 联合索引要能正确使用需要遵循最左匹配原则,否则就会导致索引失效。
  • 在 WHERE 子句中, 索引列 OR 不是索引列

执行效率从低到高的顺序为

  • All(全表扫描);
  • index(全索引扫描);
  • range(索引范围扫描);
  • ref(非唯一索引扫描);
  • eq_ref(唯一索引扫描);
  • const(结果只有一条的主键或唯一索引扫描)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ujg5XLJz-1676948199446)(../my_images/索引总结.drawio.png)]

二、从数据页角度看B+树

B+树节点存放的是数据页
File Header 中有两个指针,双向的链表
采用链表的结构是让数据页之间不需要是物理上的连续的,而是逻辑上的连续。
User Records 是怎么组织数据的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HrNpf9j5-1676948199447)(../my_images/243b1466779a9e107ae3ef0155604a17.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbHnXC1h-1676948199447)(../my_images/fabd6dadd61a0aa342d7107213955a72.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9WNi0nlG-1676948199448)(../my_images/557d17e05ce90f18591c2305871af665.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rG3JZRza-1676948199448)(../my_images/261011d237bec993821aa198b97ae8ce.png)]
在这里插入图片描述

  • 第一个分组中的记录只能有 1 条记录;
  • 最后一个分组中的记录条数范围只能在 1-8 条之间;
  • 剩下的分组中记录条数范围只能在 4-8 条之间。

在这里插入图片描述

一张表只能有一个聚簇索引

小林总结:

nnoDB 的数据是按「数据页」为单位来读写的,默认数据页大小为 16 KB。每个数据页之间通过双向链表的形式组织起来,物理上不连续,但是逻辑上连续。

数据页内包含用户记录,每个记录之间用单向链表的方式组织起来,为了加快在数据页内高效查询记录,设计了一个页目录,页目录存储各个槽(分组),且主键值是有序的,于是可以通过二分查找法的方式进行检索从而提高效率。

为了高效查询记录所在的数据页,InnoDB 采用 b+ 树作为索引,每个节点都是一个数据页。

如果叶子节点存储的是实际数据的就是聚簇索引,一个表只能有一个聚簇索引;如果叶子节点存储的不是实际数据,而是主键值则就是二级索引,一个表中可以有多个二级索引。

在使用二级索引进行查找数据时,如果查询的数据能在二级索引找到,那么就是「索引覆盖」操作,如果查询的数据不在二级索引里,就需要先在二级索引找到主键值,需要去聚簇索引中获得数据行,这个过程就叫作「回表」。

三、为什么 MySQL 采用 B+ 树作为索引?

怎样的索引的数据结构是好的?
什么是二分查找?
什么是二分查找树?
什么是B树?
什么是B+树?

MySQL 的数据是持久化的,意味着数据(索引+记录)是保存到磁盘上的,断电,数据不丢失

内存的访问速度是纳秒级别的,磁盘访问的速度是毫秒级别的,磁盘慢上万倍
磁盘读写最小单位是扇区,52B,操作系统最小读写单位是块,linux块大小是4KB,一次磁盘I/O读写8个扇区

二叉查找树的特点是一个节点的左子树的所有节点都小于这个节点,右子树的所有节点都大于这个节点
问题1、当每次插入的元素都是二叉查找树中最大的元素,二叉查找树就会退化成了一条链表,查找数据的时间复杂度变成了 O(n)
问题2、高度是I/O次数,太高了,影响查询性能
问题3、不能范围查询

平衡二叉查找树(AVL 树)
问题1、只要是二叉树,高度都太高

B树
再限制一个节点就只能有 2 个子节点,而是允许 M 个子节点 (M>2),从而降低树的高度,简单说就是多叉树
问题1、每个节点都包含了索引+记录,数据要莫没用上,要莫就要花费更多磁盘I/O次数,
问题2、用来范围查询,需要用中序遍历,设计多个节点的磁盘I/O问题

B+ 树与 B 树差异的点,主要是以下这几点:

  • 叶子节点(最底部的节点)才会存放实际数据(索引+记录),非叶子节点只会存放索引;
  • 所有索引都会在叶子节点出现,叶子节点之间构成一个有序链表;
  • 非叶子节点的索引也会同时存在在子节点中,并且是在子节点中所有索引的最大(或最小)。
  • 非叶子节点中有多少个子节点,就有多少个索引;

下面通过三个方面,比较下 B+ 和 B 树的性能区别。

1、单点查询
节点存放索引,可以存放更多索引,可以比B树更加矮胖,查询磁盘I/O次数更少

2、插入和删除效率
删除一个节点,直接删除叶子节点,不用动非叶子节点,结构更稳定,删除更快
会自平衡,因为只涉及一条路径,不需要复杂的算法

3、范围查询
为啥不说等值查询呢,因为基本一样,而范围查询就不一样了

B+树叶子节点有双向链表连接
节点内容是数据页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kg8uoRmd-1676948199450)(../my_images/dd076212a7637b9032c97a615c39dcd7.png)]

四、单表不要超过2000W行,一般靠谱

假设

  • 非叶子节点内指向其他页的数量为 x
  • 叶子节点内能容纳的数据行数为 y
  • B+ 数的层数为 z

如下图中所示,Total =x^(z-1) *y 也就是说总数会等于 x 的 z-1 次方 与 Y 的乘积

X =?

1k存标识,15k存数据,一条数据按12byte,x=15*1024/12≈1280 行

页和索引结构差不多,都会有 File Header (38 byte)、Page Header (56 Byte)、Infimum + Supermum(26 byte)、File Trailer(8byte), 再加上页目录,大概 1k 左右。

索引页中主要记录的是主键与页号,主键我们假设是 Bigint (8 byte), 而页号也是固定的(4Byte), 那么索引页中的一条数据也就是 12byte。

所以 x=15*1024/12≈1280 行。

Y=?

按一条行数据 1k 来算,那一页就能存下 15 条,Y = 15*1024/1000 ≈15。

  • 假设 B+ 树是两层,那就是 z = 2, Total = (1280 ^1 )*15 = 19200

  • 假设 B+ 树是三层,那就是 z = 3, Total = (1280 ^2) *15 = 24576000 (约 2.45kw)

  • 我们刚刚在说 Y 的值时候假设的是 1K ,那比如我实际当行的数据占用空间不是 1K , 而是 5K, 那么单个数据页最多只能放下 3 条数据。

    同样,还是按照 z = 3 的值来计算,那 Total = (1280 ^2) *3 = 4915200 (近 500w)

    行数据大小不同,最大建议值不同

    影响查询性能的还有很多其他因素,比如,数据库版本,服务器配置,sql 的编写等等

五、索引失效有哪些?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-99sw1AsG-1676948199450)(../my_images/a9e6a9708a6dbbcc65906d1338d2ae70.png)]

1、使用左模糊,|| 左右模糊

因为索引 B+ 树是按照「索引值」有序排列存储的,只能根据前缀进行比较。

2、对索引使用了函数

因为索引保存的是索引字段的原始值,而不是经过函数计算后的值,自然就没办法走索引了
从 MySQL 8.0 开始,索引特性增加了函数索引

3、对索引进行表达式计算

因为索引保存的是索引字段的原始值,而不是 id + 1 表达式计算后的值,所以无法走索引

4、对索引隐式类型转换

索引字段是字符串,但是输入的是整形
但是如果索引字段是整形,输入字段是字符串时候会用索引,因为会自动转化
MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。

5、联合索引非最左匹配

6、 WHERE 子句中的 OR

索引 OR 非索引字段,那么就是失效

六、MySQL 使用 like “%x“,索引一定会失效吗?

使用左模糊匹配(like “%xx”)并不一定会走全表扫描,关键还是看数据表中的字段。

数据库表中的字段只有主键+二级索引 == 全扫描二级索引树 type=index

如果数据库表中的字段都是索引的话,即使查询过程中,没有遵循最左匹配原则,也是走全扫描二级索引树(type=index)

七、 count(*) 和 count(1) 有什么区别?哪个性能最好?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rn3auBC5-1676948199451)(../my_images/af711033aa3423330d3a4bc6baeb9532.png)]

count该函数作用是统计符合查询条件的记录中,函数指定的参数不为 NULL 的记录有多少个
count(1)、 count(*)、 count(主键字段)在执行的时候,如果表里存在二级索引,优化器就会选择二级索引进行扫描。尽量建立二级索引

count(字段) 来统计记录个数,效率最差,全表扫描

通常在没有任何查询条件下的 count(*),MyISAM 的查询速度要明显快于 InnoDB
MyISAM,只维护一个 row_count 变量

面对大表的记录统计,解决方法

1、近似值计算
使用 show table status 或者 explain 命令来表进行估算,像谷歌统计的

2、额外表保存计数值
当我们在数据表插入一条记录的同时,将计数表中的计数字段 + 1
新增和删除操作时,我们需要额外维护这个计数表。

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

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

相关文章

C#把图片放到picturebox上的指定位置,PointToClient与PointToScreen解读

1、C#中如何把图片放到picturebox上的指定位置 构造一个跟picturebox1一样大小的Bitmap, 设置给picturebox1, 然后在上面画图 Bitmap image new Bitmap(picturebox1.Size.Width, picturebox1.Size.Height); Graphics device Graphics.FromImage(imag…

FPGA电源电流参数

一、FPGA里各个电源释义 VCCINT VCCINT是FPGA芯片的内核电压,是用来给FPGA内部的逻辑门和触发器上的电压。即芯片的晶体管开关是有核心电压提供。当内部逻辑工作时钟速率越高,使用逻辑资源越多,则核心电压供电电流会更大,可高达几…

【halcon】模板匹配和仿射变换总结

前言 模板匹配和仿射变换,经常一起使用,他们之前的位置变换一般有两种情况! 情况一 模板是一个很正的图,利用模板的位置,将歪的图像摆正。 情况二 模板和图片正不正都无所谓,只需想模板的位置&#xff0…

内网穿透/组网/设备上云平台EasyNTS上云网关的安装操作指南

EasyNTS上云网关的主要作用是解决异地视频共享/组网/上云的需求,网页对域名进行添加映射时,添加成功后会生成一个外网访问地址,在浏览器中输入外网访问地址,即可查看内网应用。无需开放端口,EasyNTS上云网关平台会向Ea…

进程间同步

并发 线程和进程都是一个调度的单位 并发进程之间的关系 交互关系之间的关系是很复杂的,假如一个进程需要等待另外一个进程的调用才可以运行,就如下面这个例子 竞争关系 上面这个区叫做临界区域 协作方式 前面我们说过异步和同步的概念 那么异…

算法笔记(十一)—— 并查集、KMP

并查集 支持集合快速合并 所有数据生成各自的集合,需要提供查询两个两素是不是属于一个集合,和集合合并操作,并查集能够在常数时间级别上对两个操作进行实现 1. 构造结构(数据指针),将自己的指针指向自己…

激光雷达介绍

全球汽车行业正在进行自动化变革,这将彻底改变交通运输的安全和效率水平。戴姆勒在S级豪华车型中引入L3级自动驾驶(L3,在特定条件下自动驾驶,人类驾驶员一旦被请求就会随时接管)是自动驾驶革命的一个重大突破。其他多家…

浅谈SQL中的union和union all

文章目录概念基础语法使用技巧区别总结概念 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。 UNION 操作符选取不同的值,如果允许得到重复的值,可以使用 UNION ALL 基础语法 -- u…

基于Spring Boot+Vue的在线考试系统(有错题训练功能)

文章目录项目介绍主要功能截图:登录系统日志在线考试错题训练考试记录题库管理试题管理角色管理用户管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、…

解决:文档根元素 “configuration“ 必须匹配 DOCTYPE 根 “null“或者“mapper” 必须匹配 DOCTYPE 根 “null”

文档根元素 "configuration" 必须匹配 DOCTYPE 根 "null 出现的原因是在配置mybatis-config.xml的时候没有把文件中的配置信息加进去导致的 解决的方式只需要在<configuration>标签前面加上如下内容: <?xml version"1.0" encoding"UT…

MySQL —— 库的操作

文章目录1. 创建数据库2. 字符集和校验规则3. 数据库的基本操作3.1 查看数据库3.2 显示创建数据库的语句3.3 修改数据库3.4 删除数据库3.5 备份&#xff0c;还原数据库4. 查看数据库的连接情况1. 创建数据库 基本语法&#xff1a; create database if not exists 数据库名 选项…

共享内存

简介&#xff1a; 共享内存两个或多个进程共享物理内存的同一块区域&#xff08;通常被称为段&#xff09;&#xff0c;由于一个共享内存段会称为一个进程用户空间的一部分&#xff0c;因此这种IPC机制无需内核介入。需要做的就是让一个进程将数据复制到共享内存段中&#xff…

数据挖掘,计算机网络、操作系统刷题笔记51

数据挖掘&#xff0c;计算机网络、操作系统刷题笔记51 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;orac…

剑指 Offer 32 - I. 从上到下打印二叉树

摘要 剑指 Offer 32 - I. 从上到下打印二叉树 剑指 Offer 32 - II. 从上到下打印二叉树 II 剑指 Offer 32 - III. 从上到下打印二叉树 III 一、二叉树的层序遍历 题目要求的二叉树的从上至下打印&#xff08;即按层打印&#xff09;&#xff0c;又称为二叉树的广度优先搜索…

解决问题:resource IDS cannot be used in a switch statement in Android library

# 发现问题在抽取lib的时候发现了这样一个问题&#xff0c;如图所示&#xff1a;1. 很正常的onClick事件的处理&#xff0c;使用的swtich语句&#xff0c;但是却报了resource IDS cannot be used in a switch statement in Android library这个问题&#xff0c;原因是...2. and…

kafka架构体系

Kafka简介 Kafka是一个由Scala和Java编写的企业级的消息发布和订阅系统&#xff0c;最早是由Linkedin公司开发&#xff0c;最终开源到Apache软件基金会的项目。Kafka是一个分布式的&#xff0c;支持分区的&#xff0c;多副本的和多订阅者的高吞吐量的消息系统&#xff0c;被广…

【单目标优化算法】樽海鞘群算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

安装vue的具体步骤

首先到官网下载一个node.js官网地址为&#xff1a;http://nodejs.cn/安装教程&#xff1a;选Node.js.runtime和 Add to Path都可以&#xff0c;建议选Add to Path添加到环境变量。这里不用勾选&#xff0c;直接下一步&#xff0c;就可以安装成功了所有的步骤都是在命令窗口执行…

【数据结构趣味多】八大排序

目录 1.直接插入排序 基本思想 代码实现&#xff1a; 直接插入排序的特性总结&#xff1a; 2.希尔排序 基本思想 代码实现 &#xff08;递归实现&#xff09; 希尔排序的特性总结 3.直接选择排序 基本思想 代码实现&#xff1a; 直接选择排序的特性总结 4.堆排序 …

Umi框架

什么是 umi umi 是由 dva 的开发者 云谦 编写的一个新的 React 开发框架。umi 既是一个框架也是一个工具&#xff0c;可以将它简单的理解为一个专注性能的类 next.js 前端框架&#xff0c;并通过约定、自动生成和解析代码等方式来辅助开发&#xff0c;减少开发者的代码量。 u…