【MySQL实战45讲4-5】索引

news2024/9/29 13:51:58

文章目录

    • 索引的定义
    • 索引的常见模型
      • 哈希表
      • 有序数组
      • 二叉搜索树
    • InnoDB的索引模型
    • 索引维护
      • 页分裂
      • 页合并
      • 页分裂和页合并的影响
      • 避免页分裂
    • 覆盖索引
    • 最左前缀原则
    • 索引下推

索引的定义

索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本500页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那寻找起来是很费劲的。同样,对于数据库的表而言,索引其实就是它的“目录”。

索引的常见模型

哈希表

哈希表是一种以**键 - 值(key - value)**存储数据的结构,只要输入待查找的键即key,就可以找到其对应的值即Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置。

不可避免地,多个key值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表

假设,现在维护者一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这是对应的哈希表索引的示意图如下:

在这里插入图片描述

图中,USER2和USER4根据身份证号算出来的值都是N,但没关系,后面还跟了一个链表。假设要查找ID_2对应的名字,处理步骤就是首先,将ID_2通过哈希函数算出N;然后,按顺序遍历,找到USER2。

需要注意的是,图中四个ID_N的值并不是递增的,这样做的好处是增加新的User时速度会很快,只需要往后追加。但缺点是,因为不是有序的,所以哈希索引做区间查询速度很慢,要全表扫描。

所以,哈希表这种结构适用于只有等值查询的场景,比如Memcached以及其他一些NoSQL引擎

有序数组

有序数组在等值查询和范围查询场景中的性能就都非常优秀。还是这个根据身份证查名字的例子,如果使用有序数组来实现的话,示意图如下所示:

在这里插入图片描述

假设身份证号没有重复,这个数组就是按照身份证号递增的顺序保存的。这个时候如果要查ID_2对应的名字,用二分法就可以快速得到,这个时间复杂度是O(log(N))

如果仅仅看查询效率,有序数组就是最好的数据机构了。但是,在需要更新数据的时候就麻烦了,往中间插入一个记录就必须得挪动后面所有的记录,成本太高。

所以,有序数组索引只适用于静态存储引擎,比如你要保存的是某一年某个城市的所有人口信息,这类不会再修改的数据。

二叉搜索树

在这里插入图片描述

二叉搜索树的特点是:父节点左子树左右节点的值小于父节点的值,右子树所有节点的值大于父节点的值。这样如果要查询ID_2的话,按照图中的搜索顺序就是按照USER_A -> USER_C -> USER_F -> USER_2这个路径得到,时间复杂度是O(log(N)).

InnoDB的索引模型

在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB使用B+树索引模型,所以数据都是存储在B+树中的。

每一个索引在InnoDB里面对应一颗B+树。

假设,我们有一个主键列为ID的表,表中又字段k,并且k上有索引。

表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下。

在这里插入图片描述

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引

主键索引(也称为聚簇索引),叶子节点存的是整行数据。非主键索引(也称为二级索引),叶子节点内容是主键的值。

主键索引和普通索引查询的区别;

  • 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
  • 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

索引维护

InnoDB的索引是以B+树的形式构建的,而且B+树的节点都是一个数据页。B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护,也就是节点分裂和节点合并。因为我们是以数据页为基本单位构造的B+树,那么B+树的节点分裂和节点合并就会造成数据页的页分裂和页合并。

页分裂

假如,现在我们插入一个新的一条记录,他的索引值是 3,那么他就要按照顺序插入到页 20 中,在索引值为 1,2 的记录的后面。而如果这个索引页已经满了,那么就需要触发一次页分裂。

页分裂是指将该页面中的一部分索引记录移动到一个新的页面中,从而为新记录腾出空间。这样可以保持 B+树的平衡和性能。

在这里插入图片描述

当我们插入一组无序的数据的时候,那么就可能导致多次的页分裂的情况。
而且某些情况下,可能会从叶子节点一路分裂到根节点(B+树的非叶子节点也存储数据,也可能分裂)。

页合并

既然会有页分裂那么就会有页合并。
页分裂发生在插入阶段,那么页合并就是发生在删除阶段。
当我们删除索引下的数据的时候,叶子节点的数据就会变得比较稀疏,此时 B+树就会触发合并操作。

在这里插入图片描述

页分裂和页合并的影响

  1. 页分裂和合并是涉及大量数据移动和重组的操作。频繁进行这些操作会增加数据库的/O 负担和 CPU 消耗,影响数据库的整体性能。
  2. 分裂和合并可能导致 B+树索引结构频繁调整,这个过程也会影响插入及删除操作的性能。
  3. 频繁的页分裂和合并可能会导致磁盘上存在较多的空间碎片,新分出的一个页一般会有很多空闲空间,使得数据库表占用更多的磁盘空间,而导致浪费。

避免页分裂

  1. 设置主键的时候尽量选择能够自增的字段
  2. 不要使用varchar类型作为ID主键
  3. 在生产全局唯一ID的时候尽量不要使用UUID,UUID不是自增的。

覆盖索引

在这里插入图片描述

回到这张图,对于有上述两个索引的表T来说,执行sql语句select * from T where k between 3 and 5,执行流程如下:

  1. 在k索引树上找到k=3的记录吗,取得ID=300;
  2. 再到ID索引树查到ID=300对应的R3;
  3. 在k索引树取下一个值k=5,取得ID=500;
  4. 再回到ID索引树查到ID=500对应的R4;
  5. 在k索引树取下一个值k=6,不满足条件,循环结束

在这个过程中,回到主键索引树搜索的过程,称为回表

如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

最左前缀原则

B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。

不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。

在建立联合索引的时候,如何安排索引内的字段顺序。这里我们的评估标准是,索引的复用能力。因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。

如果既有联合查询,又有基于 a、b 各自的查询呢?查询条件里面只有 b 的语句,是无法使用 (a,b) 这个联合索引的,这时候不得不维护另外一个索引,也就是说需要同时维护 (a,b)、(b) 这两个索引。

索引下推

现在我们知道,对于联合索引(a, b),在执行 select * from table where a > 1 and b = 2 语句的时候,只有 a 字段能用到索引,那在联合索引的 B+Tree 找到第一个满足条件的主键值(ID 为 2)后,还需要判断其他条件是否满足(看 b 是否等于 2),那是在联合索引里判断?还是回主键索引去判断呢?

  • 在 MySQL 5.6 之前,只能从 ID2 (主键值)开始一个个回表,到「主键索引」上找出数据行,再对比 b 字段值。
  • 而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在联合索引遍历过程中,对联合索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

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

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

相关文章

全开源/彩虹晴天多功能系统源码/知识付费系统/虚拟商城系统/完美可用+修复改良版

源码简介: 2024年最新全开源的彩虹晴天多功能系统源码,它可以作为知识付费系统、虚拟商城系统,完美可用,并且是修复改良版。 最让人兴奋的是,搭建这个系统完全不需要授权,不管是在国内还是国外的服务器&am…

Mybatis-Mapper接口方式

目录 配置方式和接口方式的区别 示例:Mapper接口方式实现数据库的CRUD 配置方式和接口方式的区别 Mybatis框架在配置方式的情况下,对数据库的CRUD操作直接通过SqlSession对象来操作,常用的方法有select、insert、update、delete等方法&…

企业内训|提示词工程师高阶技术内训-某运营商研发团队

近日,TsingtaoAI为某运营商技术团队交付提示词工程师高级技术培训,本课程为期2天,深入探讨深度学习与大模型技术在提示词生成与优化、客服大模型产品设计等业务场景中的应用。内容涵盖了深度学习前沿理论、大模型技术架构设计与优化、以及如何…

MySQL高阶1988-找出没所学校的最低分数要求

目录 题目 准备数据 分析数据 总结 题目 每年,学校会公布学生申请所需的最低分数要求。学校根据所有学生的考试成绩来决定其最低分数要求。 学校希望确保即使 每 一个满足分数要求的学生都申请该学校,学校也有足够的能力接纳每一个学生。学校也希望…

undeclared identifier ‘UNITY_PREV_MATRIX_M‘ - Unity Shader自己写URP,引用内部 hlsl

碰到这样的问题,居然非常淡定 这个链接里说了问题: 一个哥们A问,为什么include urp common.hlsl 提示莫名其妙 另一个哥们B说,这个issue 说了,可能是这个原因(也没正面答) 从issue我们知道&a…

手机软件何时统一——桥接模式

文章目录 手机软件何时统一——桥接模式凭什么你的游戏我不能玩紧耦合的程序演化合成/聚合复用原则松耦合的程序桥接模式桥接模式基本代码 手机软件何时统一——桥接模式 凭什么你的游戏我不能玩 时间:5月31日20点  地点:大鸟房间  人物…

从0学习React(5)---通过例子体会setState

上篇文章中,我们讲到了通过setState来更新组件的状态。我觉得上篇文章我讲的已经是比较详细的了,而且讲的很通俗易懂。但是上篇文章终归还是理论,没有实践,所以还是学了个表面而已。这篇文章我就结合一点实践来讲讲怎么使用这个se…

Java语言程序设计基础篇_编程练习题**18.37 (希尔伯特曲线)

目录 题目:**18.37 (希尔伯特曲线) 代码示例 代码逻辑解释 1. 初始化与布局 2. 绘制逻辑 3. 绘制过程 输出结果 题目:**18.37 (希尔伯特曲线) 希尔伯特曲线,由德国数学家希尔伯特于1891年第一个给出描述,是一种空间填充曲…

0108 Spring Boot启动过程

Spring Boot 的启动过程可以分为以下几个关键步骤: 1. SpringApplication 初始化 Spring Boot 应用的启动是通过调用 SpringApplication.run() 方法完成的。在这个过程中,Spring Boot 会通过 SpringApplication 类对应用进行初始化,包括设置…

ERP系统委外工单管理

1. 委外工单管理概念 1.1 定义与目的 委外工单管理是ERP系统中的一个关键组成部分,它涉及到将企业内部无法或不宜自行完成的生产任务,通过工单的形式委托给外部供应商进行加工、制造或服务的过程。委外工单管理的目的在于优化资源配置、降低生产成本、…

【Qt+Python项目构建】- 01-首次配置 Qt Creator 14.01 for Python

前言: 如何用QT实现Python的配置的交互界面。本文从0开始,进行实践的介绍。 在上一节里面,我们做了社区版本的配置: https://blog.csdn.net/yellow_hill/article/details/142597007?spm1001.2014.3001.5501 这一节&#xff0…

Android开发仿抖音底部加载进度条

Android开发仿抖音底部加载进度条 仿抖音底部加载进度条,从中间向两头伸的动画 一、思路: 自定义VideoLoadingBar控件 二、效果图: 三、关键代码: // 联系:893151960 public class VideoLoadingBar extends View …

阿布量化:基于 Python 的量化交易框架

阿布量化(AbuQuant) 是一个开源的量化交易框架,专为金融领域的研究者和交易者设计。它基于 Python 语言开发,提供了一整套从数据获取、策略开发、回测分析到交易执行的解决方案。阿布量化不仅能够帮助用户快速实现量化策略的设计与…

IDEA:Picked up _JAVA_OPTIONS: -Xmx512M

_JAVA_OPTIONS 是一个环境变量,它可以用来设置 Java 虚拟机的启动参数 如果要取消它在idea中显示,如图所示将其删除即可

C# 游戏引擎中的协程

前言 书接上回,我谈到了Unity中的协程的重要性,虽然协程不是游戏开发“必要的”,但是它可以在很多地方发挥优势。 为了在Godot找回熟悉的Unity协程开发手感,不得不自己做一个协程系统,幸运的是,有了Unity的…

MongoDB 工具包安装(mongodb-database-tools)

首先到官网下载工具包,进入下面页面,复制连接地址,使用wget下载 cd /usr/local/mongodb5.0.14/wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.6.1.tgz 安装 tar -zxvf mongodb-database-tools-rhel70-…

26个用好AI大模型的提示词技巧

如果你已深入探索过ChatGPT、Microsoft Copilot、风变AI等前沿的生成式AI工具,那么你对“prompt”(提示词)这一核心概念一定有自己的认知。 作为连接你与AI创意源泉的桥梁,“prompt”不仅是触发无限想象的钥匙,更是塑…

基于SSM的校园自助洗衣系统【附源码】

基于SSM的校园自助洗衣系统(源码L文说明文档) 目录 4 系统设计 4.1 设计原则 4.2 功能结构设计 4.3 数据库设计 4.3.1 数据库概念设计 4.3.2 数据库物理设计 第5章 系统实现 5.1 管理员功能实现 5.1.1 洗衣机管理…

远程服务器安装anaconda并创建虚拟环境

1、承接上文新用户zrcs,在服务器的zrcs文件夹下直接下载anaconda(很慢): wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh 或者选择本地下载,清华大学开源软件镜像站:https:/…

ACDsee简体中文版网盘资源下载(含教程)

如大家所熟悉的,ACDSee是一款集看图、编辑和管理于一体的软件,其凭借着打开速度快、管理功能强、操作界面友好简单等等优势,广受用户的喜欢。目前最新为ACDSee 2024版本。 一、文件管理 ACDSee数据库在文件管理方面表现出色。它可以帮助用户…