当前位置: 首页 > news >正文

Mysql(一):深入理解Mysql索引底层数据结构与算法

众所众知,MySql的查询效率以及查询方式,基本上和索引息息相关,所以,我们一定要对MySql的索引有一个具体到数据底层上的认知。

这一次也是借着整理的机会,和大家一起重新复习一下MySql的索引底层。

本节也主要有一下的几个内容:

  1. 索引数据结构红黑树,Hash,B+树详解
  2. 千万级数据表如何用B+树索引快速查找
  3. 聚集索引&非聚集索引到底是什么
  4. 为什么总推荐使用自增主键做索引
  5. 联合索引底层数据结构又是怎样的
  6. Mysql最左前缀优化原则是怎么回事

各位看官可以各取所需,希望能够对大家有所帮助。

一句话总结:索引是帮助MySQL高效获取数据的排好序数据结构

为什么需要索引

在这里插入图片描述

各位都知道,对一个没有索引的表来说,我们只能按行查找。

这似乎看起来也不会慢嘛,一个个往下找嘛。

但是问题在于,对于MySql来讲,数据是存在磁盘的,数据存在磁盘是逻辑上的连续,而不是物理上的连续。
假设我们要执行以下的Sql

select * from t where t.col2 = 89

那我们需要进行多次I/O到磁盘中找我们所需要的数据,那这就会导致我们的查询速度很慢。

注意:和磁盘进行I/O是一件很慢的事情。

索引的数据结构

我们知道,索引的存在,是为了帮助我们能够快速的获取数据的排好序数据结构

有这种功能的,我们平时学的数据结构中,主要有下面几个:

  • 二叉树
    • 二叉排序树
    • 平衡二叉树
  • 红黑树
  • Hash表
  • B-Tree
  • B+ Tree

对于二叉树和红黑树来说,两个的区别在各位学习HashMap的时候,就应该都知道了,这里我们就直接跳过。

但是,对于这两者来说,都有一个很严重的问题

  • 随着数据量的增大,树的高度会逐渐增大。

在这里插入图片描述

就比如上面这棵红黑树,你要找这个0007,你是不是要进行4次I/O,这肯定是没办法接受的。

所以我们的目标,是能够尽可能的把更多的数据一起放到树的每一层,来减少我I/O的次数

B-Tree

B树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度会相比二叉树来说,会矮很多

在这里插入图片描述

B树的每一个节点,其实可以理解成一个K-V

相比于红黑树,由于每一层能够存储的数据量多了,高度肯定是变低了,磁盘I/O次数少了,性能就提升了。

看似不错,但是几个问题:

  • 首先我们要知道,MySql为了能够更快速的查询数据,会将数据通过内存页的方式读入到内存中,一个页是16K。可以通过以下语句查看

    SHOW GLOBAL STATUS like 'Innodb_page_size';
    

    在这里插入图片描述

  • 我们的每一个节点都存了数据,如果这个数据稍微的打了一点,那我这一页才能存多少数据啊,这种方式就会导致我们的B树的高度会有问题。

  • 还有一个问题,如果是进行范围查找呢,B树似乎并不是很方便。

所以,MySql并不是以B树作为我们索引的数据结构

B+ Tree

基于上面的问题,我们引出了B+树

在这里插入图片描述

B+树相比于B树,有两个特点:

  • B+树的只有叶子节点存储数据,其他节点只存储索引(冗余)
  • B+树的叶子节点是一个双向链表。

我们先看看第一个特点,其实B+树的非叶子节点,和我们的跳表差不多, 每个节点都不存储数据,只是为了构建这个B+树。那这样带来了什么好处呢?

前面我们说的,mysql的内存页是16KB,也就是说,每次我们一个节点最多存储16KB的索引,假设我们用bigint作为索引值,也就是8个字节,加上向下的指针,大概是6个字节

在这里插入图片描述

算出来,16KB / 14B = 1170。

下面的带数据的叶子节点,正常也不会太大,我们就算一个1KB,算出来就是16个

1170 * 1170 * 16 = 21,902,400

可以看到,当树的高度为3的时候,就可以通过3次查询覆盖2000万的数据。

所以,对于B+树来说,相比于B树,更加的矮壮。

同时,因为下面是一个双向链表,对于范围查询来说,是不是能够更加快速的查出结果。

Hash

在这里插入图片描述

默认来说,mysql都是使用B Tree来存储索引的,但是你仔细看,其实是可以选择Hash的

对于Hash的话,其实大家都不会陌生。

在这里插入图片描述

Hash的特点,就是查的够快,只要一次就能查出来

缺点也很明显,Hash冲突啊,不支持范围查找。

索引是怎么存储的

因为现在MyISAM基本上没遇到过,所以这里只对InnoDB进行介绍

注意:存储引擎是基于表的,而不是数据库

在这里插入图片描述

我们打开mysql对应的文件位置,进入到里面的data,由于我目前是在test库,所以点进去test文件

在这里插入图片描述

我们可以看到,对应的表有这两个文件

  • .frm:表结构信息
  • .ibd:数据和索引

.ibd文件其实就是存储我们整张表的所有数据,他会通过B+树的方式进行存储

换句话说,表数据文件本身就是按B+Tree组织的一个索引结构文件,其实也就是我们的聚集索引

这里可以简单的说明这个聚集的概念:

  • 聚集索引,其实就是将索引和文件放在同一个文件里,像InnoDB就都放在.ibd文件中

  • 而相对应的,叫做非聚集索引,也就是索引和文件不放在同一个文件里,在MyISAM中就是这么设计的,索引在.MYD文件,数据在.MYI文件中。

    在这里插入图片描述

  • 而对于InnoDB的二级索引,其实也是非聚集索引

建议InnoDB表必须建主键

知道了索引是怎么存储的,那我们也就能知道,为什么建议InnoDB表必须建主键

如果有了主键,我们可以直接根据主键生成一个聚集索引,来保存我们的数据。

所以在大多数情况下,聚集索引 = 主键索引

没有主键是怎么存储的

InnoDB表没有主键,也是可以建表的

如果没有主键,它会从第一列开始找,如果第一列所有数据都不相等,他就会直接拿第一列来组织B+树

如果第一列没选到,就继续往后,如果都没选到,它会帮你建一个隐藏列,隐藏列给每一行一个唯一的ID,然后通过这个隐藏列来构建B+树

但是,对于MySql来说,这其实不应该由它来做的。这纯属浪费资源

推荐使用整型的自增主键

整型

首先我们知道,我们通过索引找数据的过程,其实就是一个数据比大小的过程。

所以,相比于整型,其他的肯定没有它快

就那字符串来说,字符串比较是要逐位进行比较的,特别是越长的字符串,比较的次数越多,速度肯定越慢。虽然影响没有那么大,毕竟是在内存中比较的,但是肯定是有影响的。

同时,字符串的空间占用,一般要比整型的大

  • 一方面,存储的成本提高了;
  • 另一方面,按照我们上面的分析,B+树的矮壮性肯定是会受影响的。

自增

首先,我们要先知道,对于B+树来说,非顺序的插入,会增加B+树的工作,具体的话,大家可以通过数据结构网址来模拟这个过程,在这里我就不再说了。

但是,如果是顺序插入,那B+树就会一直往后去增加,这种效率肯定要比非顺序的效率高。

非主键索引(二级索引)

在这里插入图片描述

非主键索引,也成为二级索引,非聚集索引,和主键索引一样,也是才用B+树来进行存储。

不一样的是,二级索引下面的值,是存储主键的值。

这样是为了能够节省空间保持一致性

节省空间很好理解,如果把所有数据都丢进来,占用的空间太大

保持一致性也很好理解,如果把所有数据丢进来,那修改数据的时候,主键索引和非主键索引都要改,这就很麻烦。

当然,这样的索引也有一个问题,就是由于数据和索引不是在一起的,所以往往我们查出来数据之后,就需要进行回表,根据主键索引找到对应的数据。

联合索引

联合索引就是多个字段共同构成的索引

在这里插入图片描述

最左匹配原则

各位可以先想一想,如果让你来设计,你要怎么存储,来做到有序呢?

是不是就是一个字段一个字段的排序,先第一个有序,然后在考虑第二个。

那这也就引出了我们的最左匹配原则

就拿我们上面的例子,他会先比较name,然后比较age,最后比较position

SELECT * FROM employees WHERE name='Bill' and age=31;
SELECT * FROM employees WHERE age =30 AND position='dev';

从上面的图我们可以知道,第一条Sql肯定能走索引,但是第二条呢?

是不是发现了,走不了了,因为出去name了之后,这个索引已经不是有序的了

这就是我们的最左匹配原则。

那我们继续往下走,如果遇到范围查询(>,<,like左匹配)呢?

SELECT * FROM employees WHERE name='Bill' and age > 30 and position='dev';

前面两个,走索引大家应该没什么疑问,但是到了第三个呢,从上面的图看,好像没问题,

但如果是这样呢

在这里插入图片描述

是不是发现,又是无序的了

但是,这里有一个比较有意思的,如果是>=、<=、between等这些带等于的,他其实是走了索引的。

SELECT * FROM employees WHERE name='Bill' and age >= 30 and position='dev';

虽然在符合 age>= 30 条件的二级索引记录的范围里,position 字段的值是「无序」的,但是对于符合 age = 30 的二级索引记录的范围里,position 字段的值是「有序」的(因为对于联合索引,是先按照 age 字段的值排序,然后在 age 字段的值相同的情况下,再按照 position 字段的值进行排序)。

于是,在确定需要扫描的二级索引的范围时,当二级索引记录的 age 字段值为 30 时,可以通过 position = ‘dev’ 条件减少需要扫描的二级索引记录范围(position 字段可以利用联合索引进行索引查询的意思)。也就是说,从符合 age = 30 and position = ‘dev’ 条件的第一条记录开始扫描,而不需要从第一个 age 字段值为 30 的记录开始扫描。

所以,这条查询语句都用到了联合索引进行索引查询。

这其实也用到了我们另一个知识点:索引下推

索引下推,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

相关文章:

Mysql(一):深入理解Mysql索引底层数据结构与算法

众所众知&#xff0c;MySql的查询效率以及查询方式&#xff0c;基本上和索引息息相关&#xff0c;所以&#xff0c;我们一定要对MySql的索引有一个具体到数据底层上的认知。 这一次也是借着整理的机会&#xff0c;和大家一起重新复习一下MySql的索引底层。 本节也主要有一下的…...

WebMvcConfigurer配置不当导致鉴权失败

最近同事说他们有个新需求&#xff0c;需要对接口进行加解密&#xff0c;所以他给项目配置了一个拦截器&#xff0c;但这个拦截器直接导致了所有接口鉴权失败&#xff0c;每次调用接口都是提示没有session信息。 公司内的所有java项目是公用同一套基础依赖&#xff0c;所以我也…...

微信小程序毕业设计-实验室管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…...

C#:lock锁与订单号(或交易号)的生成

在弄电商类网站的时候&#xff0c;往往是根据年月日时分秒的格式生成订单号&#xff08;yyyyMMddHHmmss&#xff09;&#xff0c;为了解决并发性&#xff0c;就直接在生成订单号的区域块加上lock。 static void Main(string[] args){for(int i0; i<100; i){//GetRandomTime(…...

计算机图形学入门11:图形管线与着色器

1.什么是图形管线 把场景中的物体经过一系列的处理&#xff0c;最后一张图像的形式在屏幕上显示出来&#xff0c;这一系列过程就是图形管线(Graphics Pipeline)&#xff0c;也叫实时渲染管线(Real-time Rendering Pipeline)。如下图所示&#xff0c;为整个渲染管线的过程。 渲染…...

正解 x86 Linux 内存管理

1&#xff0c;机器解析的思路 发现网络上大量的教程&#xff0c;多是以讹传讹地讲解 Linux 内存管理&#xff1b; 都是在讲&#xff1a; 逻辑地址 -> 线性地址 -> 物理地址 这个转换关系是怎么发生的。 上面这个过程确实是程序运行时地址的翻译顺序&#xff1b; …...

springboot读取配置时,读取到了系统环境变量

在Spring Boot应用中&#xff0c;读取配置通常通过application.properties或application.yml文件进行。不过&#xff0c;Spring Boot也支持从系统环境变量读取配置&#xff0c;这使得应用可以在不同的环境中灵活配置。下面详细介绍如何在Spring Boot中读取系统环境变量。 1. 配…...

平均召回(Average Recall,AR)概述

平均召回&#xff08;Average Recall&#xff0c;AR&#xff09;概述 在深度学习中&#xff0c;平均召回&#xff08;Average Recall, AR&#xff09;是一个衡量模型在不同阈值下的召回率的综合指标&#xff0c;特别常用于目标检测任务。召回率&#xff08;Recall&#xff09;…...

WWDC 2024 回顾:Apple Intelligence 的发布与解析

一年一度的苹果全球开发者大会&#xff08;WWDC&#xff09;如期而至&#xff0c;2024 年的 WWDC 再次成为科技界的焦点。本次发布会中&#xff0c;苹果正式推出了他们在 AI 领域的全新战略——Apple Intelligence。这一全新概念旨在为用户打造“强大、易用、全面、个性化、注重…...

[Cloud Networking] SPDY 协议

文章目录 1. 背景2. SPDY 之前3. SPDY 项目目标4. SPDY 功能特点4.1 SPDY基本功能4.2 SPDY高级功能 1. 背景 TCP是通用的、可靠的传输协议&#xff0c;提供保证交付、重复抑制、按顺序交付、流量控制、拥塞避免和其他传输特性。 HTTP是提供基本请求/响应语义的应用层协议。 不…...

Linux-笔记 samba实现映射网络驱动器到Win 10

前言 之前通过网上的方法成功映射后&#xff0c;现如今在自己电脑想实现映射服务器共享文件夹到Win 10端发现对之前的方法没有总结导致细节出问题&#xff0c;特此写下笔记。 场景 在服务器编译好代码生成镜像后&#xff0c;在Win10端采用软件烧写镜像&#xff0c;但是镜像在服…...

【技巧】Leetcode 67. 二进制求和【简单】

二进制求和 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例 1&#xff1a; 输入:a “11”, b “1” 输出&#xff1a;“100” 示例 2&#xff1a; 输入&#xff1a;a “1010”, b “1011” 输出&#xff1a;“10101” 解题思路 …...

vue项目问题汇总

1.el-select&#xff1a; 下拉框显示到了top:-2183px , 添加属性 :popper-append-to-body"false" 2. el-upload: 选过的文件在使用过后记得清空&#xff0c;因为如果有limit1的时候&#xff0c;没有清空会导致不触发onchange 使用自定义上传方法http-request的时…...

Android 工程副总裁卸任

Android 工程副总裁卸任 Android工程副总裁Dave Burke宣布&#xff0c;他将辞去领导Android工程的职位&#xff0c;将重心转向“AI/生物”项目。不过&#xff0c;他并没有离开Alphabet&#xff0c;目前仍将担任Android系统开发顾问的角色。 Burke参与了Android系统的多个关键…...

Qt 6.13

作业&#xff1a; #include "mywidget.h"mywidget::mywidget(QWidget *parent): QWidget(parent) {this->setStyleSheet("background-color:white");this->resize(600,600);this->setWindowFlag(Qt::FramelessWindowHint);this->setWindowTit…...

发布自己的c#包到nuget

1)创建自己的nuget账号 NuGet Gallery | Home 2)在Rider中-->项目邮件-->properties 注意&#xff1a;必须勾选生成nuget包 3)编译后&#xff0c;将生成一个包 4)点击上传包 5)将之前的nuget包拖拽过来&#xff0c;点击上传即可&#xff0c;如果有不对的比如&#xf…...

【学习笔记】MySQL(Ⅲ)

MySQL(Ⅲ) 11、 进阶篇 —— 视图 11.1、概述 11.2、基本语法 11.3、检查选项 CASCADED 11.4、检查选项 LOCAL 11.5、视图的更新原则12、 进阶篇 —— 存储过程 12.1、概述 12.2、基本语法 12.3、系统变量 12.4、用户定义变量 …...

STM32项目分享:心率血氧手环(可报警)

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…...

前端面经总结、学习【2023秋招】

目录 1、浏览器输入URL发生了什么&#xff1f;2、跨域是什么&#xff1f;如何解决跨域问题&#xff1f;3、cookie 是什么&#xff1f;4、cookie 能做什么&#xff1f; 1、浏览器输入URL发生了什么&#xff1f; URL解析&#xff1a;判断浏览器输入的是搜索内容还是URL&#xff…...

Linux DMA-Buf驱动框架

一、DMABUF 框架 dmabuf 是一个驱动间共享buf 的机制&#xff0c;他的简单使用场景如下&#xff1a; 用户从DRM&#xff08;显示驱动&#xff09;申请一个dmabuf&#xff0c;把dmabuf 设置给GPU驱动&#xff0c;并启动GPU将数据输出到dmabuf&#xff0c;GPU输出完成后&#xf…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...