【MySQL进阶之路 | 高级篇】索引及索引的数据结构

1. 为什么要使用索引

索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本教科书的目录,通过目录可以找到对应文章的页面,而不用一页一页从头翻到尾.MySQL也是一样的道理.在进行数据查找时,首先查看查询条件是否命中某条索引,符合则通过索引查找相关数据,如果不符合,则需要全表扫描,一条一条的查找记录,直到查找到目标数据.

为了减少磁盘的I/O次数,提高查询效率,我们就需要用到索引.

2. 索引及其优点

(1). 索引

1). 索引的定义

索引是帮助MySQL高效获取数据的数据结构.

2). 本质

索引是数据结构. 可以简单理解为"排好序的快速查找数据结构". 满足特定的查找算法. 这些数据以某种方式指向数据,这样就可以在这些数据结构的基础上实现高效的查找算法.

索引是在存储引擎中实现的,因此每种存储引擎的索引不一定完全相同.(后面我们知道,像InnoDb, MyISAM等存储引擎的索引底层是b+树,而Memory的索引底层是哈希表). 并且每种存储索引不一定支持所有索引类型. 同时,存储引擎可以定义每个表的最大索引数和最大索引长度. 所有索引引擎支持每个表至少16个索引,总索引长度至少256字节.

(2). 优点

  • 类似大学图书馆建书目索引. 提高数据检索效率,降低磁盘的i/o次数. 后面我们知道,与磁盘交互的基本单位是页,使用索引时i/o次数是b+树的高度,时间复杂度O(logn),全表扫描的时间复杂度为O(n).
  • 通过创建唯一索引,可以保证数据库表中每一行数据记录的唯一性.
  • 在实现数据的参考完整性方面,可以加速表与表之间的连接. 换句话说,对于有依赖关系的子表和父表联合查询时,可以提高查询速度.
  • 在使用分组和排序子句进行数据查询时,可以显著减少查询中分组和排序的时间,降低了CPU的消耗.

(3). 缺点

增加索引也有很多不利的地方.

  • 创建和维护索引需要耗费时间,并且随着数据量的增加,所耗费的时间也会增加.
  • 索引需要占用磁盘空间,除了数据表占数据空间外,每个索引还需要占用一定的物理空间,存储在磁盘上. 如果有大量的索引,索引文件可能比数据文件更快到达最大文件尺寸.
  • 虽然索引大大提高了查询效率,同时会降低更新表的速度. 当对表数据进行增加,删除修改的时候,索引也要动态的维护,这样就降低了数据的维护速度.以InnoDB存储引擎为例,索引底层是b+树,当增加修改删除一条记录时,可能会改变树的结构,让树重新排序,当数据量非常大的时候,将会非常消耗内存.

索引可以提高查询速度,但会影响插入记录的速度.这种情况下,我们可以先删除表中的索引,然后插入数据完成后,再创建索引.

3. InnoDB中索引的推演

(1). 索引之前的查找

比如 : select 列名 from 表名 where 列名=xxx

1). 在一个页中的查找.

假设目前表中的数据非常少,所有数据都可以被放到一个页中(一个页的存储大小为16kb),在查找记录的时候可以根据搜索条件的不同分为两种情况.

  • 以主键为搜索条件.可以在页目录(页目录这个结构以后再讲)中使用二分法快速定位到对应的槽slot,然后再遍历该槽对应分组中的记录即可以快速找到指定的记录.
  • 以其他列作为搜索条件.因为在数据页中没有对非主键列建立所谓的页目录,所以我们无法通过二分法快速定位到相对应的槽,这种情况只有从最小记录开始依次遍历单链表中的每一条记录.(记录页中,记录以单链表的结构存储在一起,即一条记录不仅存储了列的真实数据,还存储了指向下一条记录的指针,可以通过这个指针找到对应的下一条记录,涉及到行格式,以后再讲)然后依次比对是否符合.这样的效率是非常低的.

2). 在多个页中查找.

大多数情况下我们表中存放的记录是非常多的,需要好多页来存放我们的数据.在多个页中查找记录可以分为两个步骤.

1. 定位到目标记录所在的页.

2. 从所在的页中查找相应的记录.

在没有索引的情况下,不论是根据主键列或者其他列的值进行查找,由于我们不能快速定位到目标记录所在的页,所以只能从第一个页开始沿着双向链表一直找下去,在每个页中根据上述查找方法去查找目标记录.因为要遍历所有的数据页,这种方式是非常耗时的.

(2). 设计索引

主键列聚簇索引.

CREATE TABLE index_demo(
c1 INT, 
c2 INT,
c3 varchar(10),
PRIMARY KEY(c1)
) ROW_FORMAT=COMPACT;

依据主键列c1创建了聚簇索引.记录行格式为COMPACT.规定了一条记录的组成部分为变长字段长度列表,null值列表,记录头信息,以及真实的数据.其中记录头信息包含record_type和next_record字段.下图简化了行格式,略去不必要的信息.

  • record_type : 记录有信息的一项属性,表示记录的类型.0表示普通记录,1表示目录项记录,2表示最小记录,3表示最大记录.
  • next_record : 记录头信息的一项属性. 表示下一条记录的地址相对于本记录地址的偏移量,即指针.

30f0726fb1694ea38ad0c03e147a3404.png

把一些记录放在页里的示意图就是 : 

a5999cf8e80d41ed82b58eea35cee14b.png

依据主键值的大小串成一个单向链表.

此时我们insert插入数据.假设一个页只能存放三条记录,只是假设,实际上可能存放很多条记录.

INSERT INTO index_demo 
VALUES (1, 10, 'yy'),
(3, 100, 'xx'),
(2, 1000, 'zz');

即使我们添加的记录主键值并不是递增的,但也会调整为主键值递增的.如果我们此时再增加一条主键值为2的记录.由于要求下一条数据页中的记录大于上一条数据页中的记录,所以在插入主键值为2的记录时需要伴随一次记录移动,也就是把主键值为3的记录移动到主页11,把主键为2的记录移动到页10.这个过程称为页的分裂.

ac5480636d94437786f4d9da2e38a4f7.png

给所有页建立目录项.

这些16kb的页在物理存储上是双向链表,是不连续的,所以如果想从这么多页中根据主键值快速定位某些记录所在的页,我们需要给它们做个目录,每个页对应一个目录项,每个目录项包含两个部分.

  • 页用户记录的最小的主键值(也可以是最大),我们用key来表示.
  • 页号,我们用page_no表示.

405de5754b71421b9f791802ca76fee4.png

4. InnoDB中索引的方案

可以为目录项建立目录页.目录项之间以单向链表存储.

1146b88c24924b0691b6d4cc049d58ce.png

从图中可以看出,我们新分配了一个页号为30的页专门存储目录项记录.

目录项记录与普通用户记录的不同点.

  • 目录项记录是record_type是1,而普通记录的是0.
  • 目录项记录只有主键值和页的编号两个列,而普通用户的有些列是自己定义的,还有些列是InnoDB自己添加的隐藏列.比如大名鼎鼎的row_id.

目录项记录与普通用户记录的相同点.

  • 二者使用的都是一样的数据页,都会为主键值生成页目录,从而在按照主键值进行查找时可以使用二分法来加快查找速度.

虽然说目录项记录只存储主键值和对应的页号,但不论怎么说,一个页只有16kb大小,存放的目录项记录也是有限的,如果表数据太大,以至于一个数据页不足以存放所有的目录项记录.所以有必要再产生目录页.

这些目录页是不连续的,如果我们表中数据记录非常多则会产生很多的存储目录项记录的页,那么我们怎么根据主键值快速定位一个存储目录项记录的页呢?所以有必要为这些存储目录项记录的页再生成一个更高级的目录.就像是一个多级目录,大目录里嵌套小目录.小目录里才是实际的数据.

cee354c36f184ccd9b78c916f6d9ec2f.png

我们可以用图来描述索引.

409351181cae4300ad232d220a56581f.png

叶子节点存放真实的数据,非叶子节点存放目录项.

页与页之间以双向链表存储,记录与记录(不论是数据项记录还是目录项记录)之间是以单向链表存储.

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

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

相关文章

基于weixin小程序校园快递系统的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,用户管理,订单管理,快递管理,快递记录管理,公告管理,基础数据管理 小程序功能包括:系统首页,…

Java毕设代码助力,让技术实现更流畅

Java毕设代码助力,让技术实现更流畅 在Java毕业设计的道路上,代码的编写往往占据了大部分的时间和精力。为了帮助同学们更专注于项目的核心逻辑和创意实现,Java毕设服务工作室专注于提供高质量的Java代码支持。 一、专业编码,助…

python-引用配置文件和日志

文章目录 前言python-引用配置文件和日志1. 给一个配置文件2. 获取配置文件信息方法3. 获取配置信息,引入日志分页功能demo4. 测试 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 …

【乐吾乐2D可视化组态编辑器】文件

1 文件 文件:文件的新建、打开、导入、保存、另存为、下载JOSN文件、下载ZIP打包文件、导出为HTML、导出为Vue2组件、导出为Vue3组件、导出为React组件(老版将不再维护)、下载为PNG、下载为SVG 乐吾乐2D可视化组态编辑器demo:ht…

HTTP协议和Nginx

一、HTTP协议和Nginx 1.套接字Socket 套接字Socket是进程间通信IPC的一种实现,允许位于不同主机(或同一主机)上不同进程之间进行通信和数据交换,SocketAPI出现于1983年BSD4.2实现在建立通信连接的每一端,进程间的传输…

mac配置修改host文件

1command 空格 输入 terminal 选中回车进入终端控制台. command 空格 2 sudo vi /etc/hosts 输入密码,进入vi编辑器修改文件 sudo vi /etc/hosts3修改内容,:wq保存退出,重启项目即可 :wq

全景图片/老照片/动漫图片一键无损放大与修复

在日常生活中,我们经常使用系统自带的图片处理软件来对图片进行缩放操作,从而实现放大或缩小图片。然而,这种方法会带来一个问题:如果原始图片较小,放大后会导致精度损失,使图片变得模糊。 近年来&#xf…

Radxa 学习摘录

文章目录 一、参考资料二、硬件知识 一、参考资料 技术论坛(推荐) 官方资料下载 wiki资料 u-boot 文档 u-boot 源码 内核文档 内核源码 原理图 二、硬件知识 Radxa 3B 主板概览 MIPI接口 MIPI CSI(Camera Serial Interface)…

MemManage_Handler 问题的解决思路

1、问题 在做一个安全类项目时发现,软件在运行一段时间后会进入"MemManage_Handler",遂开始了一系列查找。 2、解决 (1)查看堆栈数据 查堆栈的数据,发现堆栈也被破坏了,看不出来是执行哪个任务执行导致的…

mediasoup 源码分析 (八)分析PlainTransport

mediasoup 源码分析 (六)分析PlainTransport 一、接收裸RTP流二、mediasoup 中udp建立过程 tips 一、接收裸RTP流 PlainTransport 可以接收裸RTP流,也可以接收AES加密的RTP流。源码中提供了一个通过ffmpeg发送裸RTP流到mediasoup的脚本&…

centos上快速搭建zfile文件网站

什么是zfile? zfile文件网站是最方便快捷的在线目录展示程序,支持将本地文件、FTP、SFTP、S3、OneDrive 等存储在网站上展示并浏览! 本教程参考: https://docs.zfile.vip/install/os-linux复现 今天的搭建环境是centos7.9 第一…

CPPTest设计分析

目录 1 概述2 设计3 扩展Output3.1 扩展实例 1 概述 CppTest是一个可移植、功能强大但简单的单元测试框架,用于处理C中的自动化测试。重点在于可用性和可扩展性。支持多种输出格式,并且可以轻松添加新的输出格式。 CppTest下载地址Sourceforge Github地…

Java技术栈总结:数据库MySQL篇

一、慢查询 1、常见情形 聚合查询 多表查询 表数据量过大查询 深度分页查询 2、定位慢查询 方案一、开源工具 调试工具:Arthas运维工具:Prometheus、Skywalking 方案二、MySQL自带慢日志 在MySQL配置文件 /etc/my.conf 中配置: # …

云原生技术峰会:引领智能算力时代的创新浪潮

云原生技术峰会:引领智能算力时代的创新浪潮 随着云计算技术的飞速发展和智能算力的不断提升,云原生架构已成为推动企业数字化转型的重要力量。一场汇聚了业界顶尖专家和学者的云原生技术峰会成功举行,与会者共同探讨了云原生在智能算力时代…

python3用两个栈实现一个队列

栈与队列 栈:先入后出,First In First Out (FIFO) ,类似桶(入到桶底、取从桶顶) 队列:先入先出,First In Last Out (FILO) 用两个栈实现一个队列 两个桶(栈)&#x…

Shell 编程入门

优质博文:IT-BLOG-CN 【1】x.sh文件内容编写: 固定开头:#!/bin/sh; 【2】学习的第一个命令就是echo输出的意思; 【3】其实shell脚本也就是在文件中写命令,但是我们要写的是绝对路径&#xff1a…

Web渗透:逻辑越权漏洞

逻辑越权漏洞(Business Logic Vulnerability)是指攻击者利用应用程序业务逻辑中的漏洞,绕过正常的安全控制,执行未授权的操作。与常见的技术性漏洞不同,逻辑越权漏洞通常与应用程序的功能和流程有关,需要对…

Java初识集合(后续不断补充)

第一次更新时间:2024.6.26 集合概述 Java中的集合就像一个容器,专门用来存储Java对象(实际上是对象的引用,但习惯称为对象),这些对象可以是任意的数据类型,并且长度可变。其中,这些…

使用go语言来完成复杂excel表的导出导入

使用go语言来完成复杂excel表的导出导入(一) 1.复杂表的导入 开发需求是需要在功能页面上开发一个excel文件的导入导出功能,这里的复杂指定是表内数据夹杂着一对多,多对一的形式,如下图所示。数据杂乱而且对应不统一。…

基于单片机和 Arduino 平台的六自由度可控机械手臂

摘 要 : 为了降低机械手臂的设计开发难度 , 并使之尽早地投入应用 , 设计一种基于单片机和 Arduino 平台的六自由度可控机械手臂 。提出六自由度可控机械手臂的控制方案, 给出机械手臂控制系统的结构框图 。 详细设计六自由度可控机械手臂…