当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL 数据库索引技术原理初探

MySQL 数据库索引技术原理初探

来源:SegmentFault 2023-02-16 16:27:13 0浏览 收藏

来到golang学习网的大家,相信都是编程学习爱好者,希望在这里学习数据库相关编程知识。下面本篇文章就来带大家聊聊《MySQL 数据库索引技术原理初探》,介绍一下MySQL、数据库、后端,希望对大家的知识积累有所帮助,助力实战开发!

概述

什么是索引

一本书 500 页的书,如果没有目录,直接去找某个知识点,可能需要找一会儿,但是借助前面的目录,就可以快速找到对应知识点在书的哪一页。这里的目录就是索引。

所以,为什么会有索引?为了提高数据查询效率。

常见索引算法

最简单也最容易想到的索引算法就是有序数组了,我们创建一个数组,数组按照顺序排列,

img

我们要查找某一条记录,使用二分法就可以快速得到(log N),从图中我们可以看出,有序数组作为索引时,处理等值查询和范围查询时性能会非常优秀。既然这么优秀,为什么我们不使用它呢?

因为它的插入性能很差,每次往中间插入一条记录,就必须挪动后面所有的记录,这个成本太高了。

第二种算法时哈希表,哈希表时一种 KV 形式存储的数据结构,比如我们平时用的 HashMap。哈希表的思路非常简单,用一个哈希函数把Key 换算成一个确定的位置,把 V 放到这个位置就可以了。

img

我们可以看得出,哈希表这种数据结构在进行等值查询的时候,效率时非常高的,我们常用的 Redis 以及以前比较流行的 Memcached 都使用了哈希表。但是哈希表有个致命缺陷,就是对范围查询的支持性非常差,因为数据的存储时无序的,无论我们要查询的范围有多大,都必须把所有的数据全部便利一遍做个排序才行。

在讲第三种索引方式之前,我们简单了解下机械硬盘存取数据的原理

image-20210326092749979

要访问磁盘上的某个条数据,我们需要通过磁道,扇区来确定数据所在的 Block,然后通过 Offset 就可以定位到磁盘上的任意一个字节。从磁盘上读取数据时,都是以 Block 的形式读取的。这里我们可以看到,一个 Block 的大小是 512 Bytes,当然,这是针对磁盘设备的,对于 Linux 的文件系统来说,一个 Block 一般是 4KB。InnoDB 数据存取是以数据页为单位的,数据页相比磁盘 Block 要大一些,一般默认是 16KB。为了简化整个模型,我们这里抛开复杂的数据页或者文件系统 Block 概念,从磁盘的 Block 开始说起

image-20210326092835533

假设我们的数据库里面存储了 1000 条记录,每条记录占用 128 Bytes,前面我们说过,一个磁盘的 Block 能够存储 512 Bytes,也就是说,一个 Block 可以存储 4 条记录,存储这些记录,一共需要 250 个 Blocks。当我们需要查询一条数据时,最多需要从磁盘加载 250 个Blocks,想想读取 250 次磁盘会有多慢!

image-20210326092923323

为了减少对磁盘的访问次数,我们可以把所有记录的 id 单独拿出来创建一个索引 L1,这个 id 和指向原始数据的地址组成了一个新的数据结构,它的长度这里是 16 Bytes,索引也是需要存储到磁盘的,一个 Block 可以存储 32 条索引记录,1000条索引记录需要 (1000/32=31.25) 32 个 Blocks。这时候我们需要查询一条数据时,就变成了先从索引表中查询出对应数据的指针(读取 32 个 Blocks),然后再去源数据表中根据地址直接读取记录所在的数据块(1个Block)。看,通过增加一个索引,我们成功的将磁盘读取次数从 250 次减少到了 33 次。我们可不可以让读取磁盘次数更少呢,当然可以!再增加一级索引呗!

image-20210326093000953

新添加的这一级索引指向了前面我们添加的索引 L1 所在的数据块。在这一级索引上,每一条记录都对应了 L1 索引所在的数据块,也就是 32 条L1索引记录所在的位置。1000条数据在这里还剩多少呢,前面我们说过,1000条数据共需要 32 个 L1 索引 Block,对应在这里也就是需要 32 条 L2 索引,总空间占用才 32x16 = 512 Bytes,刚好一个磁盘 Block 大小。到这一级,我们需要访问磁盘的次数就变成了 1+1+1=3 了!

我们把上面这个图抽象一下,去掉其中的细节,

image-20210326093031086

当我们把它旋转一下的时候,我们就得到了这样一种数据结构

image-20210326093055460

看!这不就是一棵树嘛

image-20210326104832514

说到树,我们知道最简单的就是二叉树了,二叉树的典型特点是有序,左子树小于父节点,右子树大于父节点。无论是搜索效率还是插入效率,二叉树的效率都是非常高的(log N),但是大多数数据库并不使用它,这是为什么呢?

因为我们的数据是存储在磁盘上的,程序运行过程中要使用数据,必须从磁盘把数据加载到内存才行。二叉树随着节点的增多,树的高度页越来越高,对应到磁盘访问上,我们就需要访问更多的数据块。当我们的数据存储在机械硬盘的时候,从磁盘随机读取一个数据块就需要 10ms 左右的寻址时间,也就是说,如果我们扫描一个 100 万行的表,单独访问一行就可能需要 20 个 10ms,可想可知这个查询会有多慢!

_images/binary-tree.png

当然,我们这棵树可不是二叉树,因为每个分支都可能有很多条记录。我们把这种树称为 N 叉树,也就是多叉树,树的分叉越多,每个节点的子节点就越多,树的高度就越低。因此就有B-Tree 和 B+Tree。

Image 1

B+Tree 索引

讲到 B+ 树索引,我们就不得不一下 B 树索引,前面我们简单了解了下二叉树,我们知道,二叉树的树高太大,会严重影响查询效率,为了解决这个问题,就有了 B 树

索引

B树是为了更好的实现索引结构而被创造出来的,它大幅度减少了磁盘访问的次数。除此之外,它还充分利用了“局部性原理”(数据有序,相关性强)。

局部性原理:在一段时间内,整个程序的执行仅限于程序的某一部分,相应的,执行所访问的存储空间也局限于某个内存区域。局部性原理分为时间局部性和空间局部性。

  • 时间局部性:被引用过一次的存储器位置在未来会被多次引用(通常在循环中)
  • 空间局部性:如果一个存储器的位置被引用,那么将来它附近的位置也会被引用

利用局部性原理可以实现磁盘预读,前面提过,InnoDB一次是读取一页的数据(16K),也就是说,每次我们实际加载的数据比我们需要的可能会多一些,这些数据可以缓存在内存中,未来我们需要读取的时候,就可以避免磁盘 IO 了。

但是B树有着下面两个缺陷

  • 每个节点都存储数据,因此索引会变得很大,每个 Block 能够容纳的索引数就会变少,我们也就需要访问更多次的磁盘
  • 对范围查询支持不是很好,需要中序遍历

为了解决这两个问题,B+ 树就诞生了,

索引

B+树只有叶子节点才存储数据,其它节点不再存储数据,所有的叶子节点都在同一层上,叶子节点之间增加了一条链表,通过这条链表,我们就可以依次直接遍历所有数据。这些变化,让 B+ 树拥有了比 B 树更优秀的特性:

  • 非叶子节点不存储数据,可以实现查询加速(一次磁盘访问可以读取更多的索引记录,减少磁盘访问)
  • 范围查询更加优秀,可以顺着叶子节点的链表直接查询出某一个范围内的数据

B+数是一棵 N 叉树,N 的大小取决于索引字段的大小,以整数字段索引为例,N≈1200,当树高为 4 的时候,就是 1200 的 3 次方,17亿。一个 10 亿行的表上一个整数字段索引,查找一个值最多只需要访问 3 次磁盘(树根一般在内存中)。

MySQL 的 InnoDB 就是采用了 B+ 树作为默认的索引算法,前面我们说了,B+树只在叶子节点存储数据,但是这个叶子节点存储的是什么数据呢? 我们根据叶子存储数据类型的不同分为两种索引

  • 主键索引,也成为聚簇索引(Clustered index),在叶子节点存储的是整行数据
  • 非主键索引,也成为二级索引(Secondary index),叶子节点存储的是主键的值

image-20210326115557786

正因为在 InnoDB 中,我们的数据也是存储在一个索引(主键索引)里的,因此,我们称 InnoDB 是索引组织表。二级索引存储的是数据的主键,当我们使用二级索引查询一条数据的时候,首先会从二级索引中查询到这条记录的 ID,然后拿这个 ID 去主键索引查询真正的数据,我们称这个过程为 回表。

因为二级索引存储的是主键的 ID,因此通常我们会选择 integer 或者 bigint 等整型类型作为主键,这样做的目的是可以减少二级索引占用空间的大小。如果用字符串作为主键,可想可知二级索引会有多大!

除了上面这个外,通常要求主键一定是要自增的,这样做是为了保证主键的有序,每次插入数据都是追加到 B+ 树,避免页分裂(如果数据页满了,则需要申请新的数据页,然后挪动部分数据过去,这个过程叫做 页分裂)的产生,提高数据写入性能。

从上面讲的这些,我们可以想到下面几个优化索引的技巧

  • 索引应该尽可能小,这样一次磁盘读取可以返回尽可能多的索引数据,在查询数据时就可以减少磁盘 IO
  • 大表查询尽可能的使用索引,不使用索引就会造成全表扫描,想想一个查询,需要遍历几百万数据,读取成千上百次磁盘会有多慢
  • 如果可能,尽量使用主键索引进行查询,使用主键索引可以直接触达数据,不需要执行回表,减少磁盘 IO
  • 如果索引中包含了我们要查询的所有字段,那就不需要在进行回表,可以减少磁盘 IO,显著提升查询性能,我们把这种查询数据都在索引里面的情况叫做覆盖索引

总结

这次分享中,我们先简单介绍了下两种简单的索引结构,然后从数据在磁盘的存储说起,从没有索引到建立多级索引,解释了为什么会出现树索引以及B树索引和 B+树索引,最后我们介绍了下 InnoDB 中关于主键索引和二级索引的概念和几个优化索引的技巧。

本文将会持续修正和更新,最新内容请参考我的 GITHUB 上的 程序猿成长计划 项目,欢迎 Star,更多精彩内容请 follow me


以上就是《MySQL 数据库索引技术原理初探》的详细内容,更多关于mysql的资料请关注golang学习网公众号!

版本声明
本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
Intel PAUSE 指令变化如何影响 MySQL 的性能Intel PAUSE 指令变化如何影响 MySQL 的性能
上一篇
Intel PAUSE 指令变化如何影响 MySQL 的性能
EMR-StarRocks 与 Flink 在汇量实时写入场景的最佳实践
下一篇
EMR-StarRocks 与 Flink 在汇量实时写入场景的最佳实践
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • PPTFake答辩PPT生成器:一键生成高效专业的答辩PPT
    PPTFake答辩PPT生成器
    PPTFake答辩PPT生成器,专为答辩准备设计,极致高效生成PPT与自述稿。智能解析内容,提供多样模板,数据可视化,贴心配套服务,灵活自主编辑,降低制作门槛,适用于各类答辩场景。
    21次使用
  • SEO标题Lovart AI:全球首个设计领域AI智能体,实现全链路设计自动化
    Lovart
    SEO摘要探索Lovart AI,这款专注于设计领域的AI智能体,通过多模态模型集成和智能任务拆解,实现全链路设计自动化。无论是品牌全案设计、广告与视频制作,还是文创内容创作,Lovart AI都能满足您的需求,提升设计效率,降低成本。
    20次使用
  • 美图AI抠图:行业领先的智能图像处理技术,3秒出图,精准无误
    美图AI抠图
    美图AI抠图,依托CVPR 2024竞赛亚军技术,提供顶尖的图像处理解决方案。适用于证件照、商品、毛发等多场景,支持批量处理,3秒出图,零PS基础也能轻松操作,满足个人与商业需求。
    33次使用
  • SEO标题PetGPT:智能桌面宠物程序,结合AI对话的个性化陪伴工具
    PetGPT
    SEO摘要PetGPT 是一款基于 Python 和 PyQt 开发的智能桌面宠物程序,集成了 OpenAI 的 GPT 模型,提供上下文感知对话和主动聊天功能。用户可高度自定义宠物的外观和行为,支持插件热更新和二次开发。适用于需要陪伴和效率辅助的办公族、学生及 AI 技术爱好者。
    34次使用
  • 可图AI图片生成:快手可灵AI2.0引领图像创作新时代
    可图AI图片生成
    探索快手旗下可灵AI2.0发布的可图AI2.0图像生成大模型,体验从文本生成图像、图像编辑到风格转绘的全链路创作。了解其技术突破、功能创新及在广告、影视、非遗等领域的应用,领先于Midjourney、DALL-E等竞品。
    56次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码