学习笔记-浅谈MySql索引的数据结构与算法和索引的介绍_设计一个索引数据结构以及相应的算法-程序员宅基地

技术标签: java  mysql  性能调优专题  b树  

索引的数据结构

B-Tree(B树)

  B树是一种自平衡的树,为了实现高效的访问磁盘存取而设计的多叉平衡搜索树,B树中的每个节点的元素和子树都是有限的,除了跟节点,每个节点最多有M个元素,每个内部节点最少有 ⌈M/2⌉个子节点,向上取整。

B-Tree特点

  1. 根节点至少有两个子节点
  2. 树中每个节点至少有M(M>=2)个子节点
  3. 除根节点和叶子节点,其他每个节点至少有ceil(m/2)个子节点(向上取整)、
  4. 所有的叶子节点都在一层上
  5. 假设每个非叶子节点中包含有n个关键字信息
    • ki(i=1…n)且关键字按升序排序K(i-1) < Ki
    • 关键字的个数n必须满足:[ceil(m/2)-1] <= n <= m-1
    • 非叶子节点的指针:p[1],p[2]…p[m]其中p[1]指向关键字小于k[1]的子树,p[m]的指向关键字大于k[m-1]的子树,其他p[i]指向关键字属于(k[k(i-1),k(i)])的子树。

B-Tree优点

  1. 叶子节点具有相同的深度,叶子节点的指针为空
  2. 所有索引元素不重复
  3. 节点中的数据索引从左至右递增排序
    B-Tree 结构

B+Tree(B+树)

  B+树是一种特殊的B树,和B树的性质差别多,只是对B树的每个非叶子节点有指针域和数据域,而B树非叶子节点只有指针域而没有指针域,还有就是没有节点都会出现在叶子节点上,并且每个叶子节点都是用双链表的形式,方便更好的做范围查询。

B+Tree特点

  1. 非叶子节点的子树指针域关键字树相同
  2. 非叶子节点的子树指针p[i],指向关键字值[k[i],k[i-1]]的子树
  3. 非叶子节点仅使用索引。数据都保存在叶子节点中
  4. 所有叶子节点均有一个指向下一个叶子节点的指针和指向前节点的指针

B+Tree优点

  1. 非叶子节点不存储数据,只存储索引,可以存储更多的索引
  2. 叶子节点用指针连接,提高区间访问的性能
  3. 查询效率稳定、磁盘读写代价更低
    B+Tree 结构

Hash

  Hash索引是一种hash散列结构,它的存取速度非常快,Hash只支持等值查询,Hash索引只存储hash值适合字段长度较长,且字段选择性好的等值查询。

Hash优点

  1. 对索引的key进行一次hash计算就可以定位出数据的存储位置
  2. 很多时间Hash索引要比B+树索引更高效

Hash缺点

  1. 仅能满足等值查询‘in’,‘=’,不支持范围查询
  2. hash冲突问题

红黑树

  红黑树是一种自平衡的二叉查找树,是一种特殊化的AVL树,都是进行查询和删除操作时通过特定操作二叉树的平衡,插入和删除。它虽然比较复杂的,但它的最坏情况运行时间也非常良好的,并且在实践中是高效的。缺点就是当数据量大的时候层次很深(n个节点开平方根向上取整)

红黑树特点

  1. 每个节点不是黑色就是红色
  2. 根节点是黑色
  3. 每个叶子节点(NIL)是黑色
  4. 如果一个节点是红色的,则它的子节点必须是黑色的
  5. 从一个节点到改节点子孙节点的所在位置包含相同树木的黑节点
    红黑树结构

Mysql的引擎

MyISAM

  MyISAM索引文件和数据文件是分离的(非聚集)
MyISAM引擎下索引与数据关系图

InnoDB

  InnoDB表数据文件本身就是按照B+Tree组织的一个索引文件,聚集索引叶子节点包含了完整的数据记录
InnoDB引擎下索引与数据关系图

MyISAM和InnoDB的异同

  1. InnoDB支持事务,MyISAM不支持事务
  2. InnoDB支持外键,MyISAM不支持外键
  3. InnoDB是聚集索引,MyISAM是非聚集索引
  4. InnoDB不保存表的具体行数,而MyISAM会专门维护应该变量保存表的记录数
  5. InnoDB支持行锁(默认),MyISAM支持表锁(默认)
  6. InnoDB表的必须有唯一的主键,而MyISAM非必须

MySql的索引辨析

索引分类

按数据结构划分: B+Tree索引、Hash索引、Fulltext索引(全文索引5.6后,MyISAM和InnoDB都支持)、R-Tree索引


按物理存储划分: 聚集索引、非聚集索引


按逻辑角度划分: 主键索引、唯一索引、普通索引、联合索引等

聚集索引和非聚集索引

聚集索引(聚簇索引)

  InnoDB中使用的了聚集索引,就是将表的主键用来构建一棵B+树,并且将整张表的行记录数据存放在该B+树的叶子节点中。聚集索引的叶子节点就是数据页,换句话说数据页存放的就是完整的每行记录。
聚集索引

聚簇索引的优点
  1. 通过聚簇索引能获取完整的整行数据。
  2. 对于主键排序查询和范围查询速度非常快
如果没有主键如何选择主键

  通常InnoDB索引不管是任何书籍和公司的MySql开发规范都强烈要求我们建一个主键并且最后是自增主键。因为是具有主键构建的B+Tree来存储数据,如果建表的时候没有主键,就会选择建表的唯一索引,选择唯一索引的字段为主键,如果建表的时候没有唯一索引,就会选择一个隐含列RowId(随机数)来做主键,然后就用这个主键来建立聚集索引。

非聚集索引(非聚簇索引)

  MyISAM就是使用了非聚集索引,B+Tree的叶子节点的数据域不是存储这条数据的记录,而是存向指向数据的一个key。
非聚集索引

辅助索引(二级索引)

  聚簇索引只有在搜索条件中有主键是才能发挥作用,但是我们在实际的开发中的时候,大多数筛选查询都不是用id,都是用实际的义务字段。此时我们就需要根据义务需要,此时的B+Tree的叶子节点的数据域就会存主键的ID的地址,如果没有进行覆盖就会回表进行获取索引的数据。

回表和MRR

回表

  辅助索引的存在并不影响数据在聚簇索引中的组织,因为一张表可以有多个复杂索引。当通过辅助索引来寻找数据,InnoDB存储引擎会遍历辅助索引并通过叶子级别的节点干活去指向主键索引的主键,然后通过主键索引来找到一个完整的行记录,就称为回表。
  为什么需要回表一次,直接把完整的用户记录放到不就行了吗?如果把完整的记录都存在叶子节点,但是太占地方了,相当于没创建一个索引都需要拷贝一遍,并且如果有修改所有的索引都需要进行调整了,因此性能很低。

MRR

  很明显如果每查询一条记录都进行一次回表这样效率就比较低,MySql底层了Disk-Sweep Multi-Range Read(MRR,多范围读取)的优化措施,即先读取一部分二级索引记录,将它们的主键值排好序之后再统一执行回表操作。这样就减少了回表的次数,这样就节省一些IO开销。使用这个MRR优化措施的条件比较可靠,索引我们直接认为读取每条二级索引记录就立即执行回表操作。

主键索引

  主键索引它是一种特殊的索引,不允许有空值,就是我们建表的主键基于这个id来作为主键索引。

普通索引

  最基本的索引,没有任何限制


alter table table_name add index index_name(coll_name);


create index index_name on tbale_name(coll_name);

唯一索引

  与普通索引lies,不同的是所有列必须有唯一的值,但允许有空值


alter table table_name add unique index index_name(coll_name);


create unique index index_name on tbale_name(coll_name);

联合索引(组合索引/复合索引)

  在实际的开发中可能需要构建一个索引需要多个字段,例如index(a,b)就是将a,b两个组合起来构成一个索引。注意:多个字段都是建立在一棵B+树上的。

什么是最左匹配原则

  当建立了一个联合索引后,但是查询的时候必须遵守最左匹配原则,但满足了左边的字段,才会使用索引进行查询。

最左匹配原则示例

假设index(a,b,c)

where语句 索引是否被使用
where a = 3 Y,使用到a
where a = 3 and b = 5 Y,使用到a,b
where a = 3 and b = 5 and c = 4 Y,使用到a,b,c
where b = 3 或 where b = 5 and c = 4 或 where c= 4 N
where a = 3 and c = 4 Y,使用到a,但是c不可以,b中断了
where a = 3 and b > 5 and c = 4 Y,使用到a,b c不能在范围之后,b中断了
where a = 3 and b like ‘kk%’ and c = 4 Y,使用到a,b,c
where a = 3 and b like ‘%kk’ and c = 4 Y,使用到a
where a = 3 and b like ‘%kk%’ and c = 4 Y,使用到a
where a = 3 and b like ‘k%kk%’ and c = 4 Y,使用到a,b,c

全文索引

  它将存储于数据库的整本书或整篇文章中的任意内容信息找出来的技术。MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引。从InnoDB 1.2.x版本开始,InnoDB存储引擎开始支持全文检索,对应的MySQL版本是5.6.x系列。


alter table table_name add fulltext index index_name(coll_name);


create fulltext index index_name on tbale_name(coll_name);


注意:不管什么引擎,只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。

自适应Hash索引

  InnoDB存储引擎除了我们前面所说的各种索引,还有一种自适应哈希索引,我们知道B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般为3 ~ 4层,故需要3 ~ 4次的IO查询。
  所以在InnoDB存储引擎内部自己去监控索引表,如果监控到某个索引经常用,那么就认为是热数据,然后内部自己创建一个hash索引,称之为自适应哈希索引( Adaptive Hash Index,AHI),创建以后,如果下次又查询到这个索引,那么直接通过hash算法推导出记录的地址,直接一次就能查到数据,比重复去B+tree索引中查询三四次节点的效率高了不少。
  InnoDB存储引擎使用的哈希函数采用除法散列方式,其冲突机制采用链表方式。注意,对于自适应哈希索引仅是数据库自身创建并使用的,我们并不能对其进行干预。

什么是密集索引和稀疏索引

密集索引: 叶子节点保存的不只是建值的,还保存了位于同一行记录里的其他列信息,由于密集索引决定了表的物理排列顺序,一个表只有一个物理排序顺序,所以一个表只能创建一个密集索引。
稀疏索引: 叶子节点仅保存了键位信息以及改行数据的地址,由于的稀疏索引只保存了键位信息和机器主键
  MyISAM存储索引,不管是主键索引,唯一索引还是普通索引都是稀疏索引;InnoDB存储引擎有且只有一个密集索引,所以密集索引就是InnoDB存储引擎里的聚簇索引,稀疏索引就是InnoDB存储里面的普通二级索引。

辨析索引覆盖(覆盖索引)

  覆盖索引是我们经常听见的名称,InnoDB存储引擎支持覆盖索引,就是从二级索引中就可以查询得到的记录,不需要再进行回表去聚簇索引中获取记录,因此可以减少了大量的IO操作,覆盖索引可以视为一种索引优化方式,而并不是一种索引类型

索引的代价

  世界上从来没只有好处而没有代价的东西,虽然索引是一个好东西,但是我们在使用的时候一定要先了解使用索引的代价,它在空间上和时间带来的影响。

时间上的代价

  每一次对表中的数据进行增、删、改操作时都需要去修改各个B+Tree索引,而且B+Tree每层节点都是安装索引列的值从小到大的顺序而组成溜了双向链表。所以存储引擎需要额外的时间进行一些移位,页面分裂,页面回收等相关操作来维护号B+Tree的平衡。这样的对B+Tree的维护相关的操作必然对性能造成一定的影响。

空间上的代价

  每建立一个索引都要它建立一棵B+Tree,每一棵B+Tree的每一个节点都是一个数据页,一个页默认会占用16KB的存储空间,一棵很大的B+Tree由许多的数据页存储空间。

MySql的范式介绍

范式设计

什么设计范式

  范式来自英文Normal Form检测NF。MySql是关系型数据库,但是设计一个好的关系,必须满足一定的约束条件,此约束已经形成了规范,分层好几级,一级比一级要求严格。满足了这些规范的数据库是简洁的、结构明晰的同时,不会范式增、删、改操作异常。目前关系型数据库六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)、第五范式(5NF)。

第一范式

  第一范式关系必须满足索引属性不可再分即数据向不可分

第二范式

  第二范式必须满足第一范式,要求数据库中的每个实例或行可以被唯一地区分。通常在实现说需要在表上加一个列,来存储各个实例的唯一标识。

第三范式

  第三范式必须满足第二范式,指每个非主属性即不部分依赖也不传递依赖业务主键,也就是在第二范式的基础上消除非主键对主键的传递依赖。

反范式设计

  在这个互联网时代对查询响应的速度要求非常高,很明显在实际的业务查询中会大量的表存在关联查询,而大量的关联查询在数据量很大的时候非常影响性能;所谓反范式化就是为了性能考虑和读取效率得考虑而适当对数据库的设计范式要求进行违反,进行少量的冗余,也就是通常说的空间换时间

范式化和反范式化的比较

范式化的优缺点

优点
  1. 范式化的更新操作通常比反范式化要快。
  2. 当数据较好的范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据。
  3. 范式化的表通常比较小,可以更好的放在内存里,所以执行操作会更快。
  4. 很少有多余的数据就检索列的表数据更少需要distinct或者group by语句。
缺点
  1. 范式化设计通常需要关联
  2. 关联的表比较多情况下一些索引策略无效。

反范式化的优缺点

优点
  1. 反范式设计可以减少表的关联
  2. 可以更好的进行索引优化
缺点
  1. 存在数据冗余及数据维护异常
  2. 对数据的修改需要更多的成本
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40777329/article/details/125835599

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签