MySQL索引、架构(redolog, undolog, binlog)

索引

存储结构

hash表

hash表适合进行等值查询,而不是适合范围查询(公司业务大多数是范围查询),因为它的排列是无序的。

二叉树

二叉树及其N多的变种都不能支撑索引,
原因是树的深度无法控制,深度过深导致io次数变多,影响数据读取的效率。

B树

所以考虑使用多叉树:B树

在这里插入图片描述

每个节点是一个磁盘块,一个节点上有两个升序的主键值和数据,还有3个指向子节点的指针。
性能逼近二分查找。

查找主键值为28的过程:
1、根据根节点找到磁盘块 1,读入内存。【磁盘 I/O 操作第 1 次】
2、比较关键字 28 在区间(16,34),找到磁盘块 1 的指针 P2。
3、根据 P2 指针找到磁盘块 3,读入内存。【磁盘 I/O 操作第 2 次】
4、比较关键字 28 在区间(25,31),找到磁盘块 3 的指针 P2。
5、根据 P2 指针找到磁盘块 8,读入内存。【磁盘 I/O 操作第 3 次】
6、在磁盘块 8 中的关键字列表中找到关键字 28。

缺点:
1、每个节点都有key,同时也包含data,而每个页存储空间是有限的,如果data比较大的话会导致每个节点存储的key数量变小
2、当存储的数据量很大的时候会导致深度较大,增大查询时磁盘io次数,进而影响查询性能

B+树

所以引入B+树:

B+Tree是在BTree的基础之上做的一种优化,变化如下:
1、B+Tree每个节点可以包含更多的节点,这个做的原因有两个,第一个原因是为了降低树的高度,第二个原因是将数据范围变为多个区间,区间越多,数据检索越快
2、非叶子节点存储key,叶子节点存储key和数据
3、叶子节点两两指针相互连接(符合磁盘的预读特性),顺序查询性能更高

在这里插入图片描述
注意:在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对 B+Tree 进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

索引分类

  • 主键索引:主键最好设置自增,减小维护成本(避免页的分裂和合并)

  • 唯一索引:索引列的所有值都只能出现一次,值可以为空。建表时设置 unique key 会自动生成索引。

  • 普通索引:基本的索引,值可以为空,没有唯一性限制。会产生回表的情况(遍历两颗B+树)
    (覆盖索引:当要查询的值在普通索引所在B+树时,只需要遍历一棵B+树)

  • 全文索引:MyISAM支持,Innodb在5.6之后支持
    索引类型 FULLTEXT。全文索引可以在varchar, char, text类型的列上创建。

  • 组合索引:多列值组成一个索引,专门用于组合搜索(最左匹配原则)
    比如name,age组合索引,只有name匹配上了,才会去匹配age,此为最左匹配原则。

面试难点

回表

先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树。
二级索引无法直接查询到所有列的数据,先扫描二级索引树找到对应主键id,再通过主键id找到所有列的数据。

覆盖索引

比如一个table含有两列 id, name 。
那么在创建这个表的时候,会创建 id索引树,name索引树。
如果执行下面语句:
select * from table where name = “jack”;
因为搜索的是 “*”,"*"所对应的数据必须要在主键这棵树上才会体现,所以会先在name B+树中找到id,再去id B+树中取出所有数据。(回表)

实际上,只需要找到name对应的id,而id在name索引树上就有。
改变SQL: select id from table where name = “jack”;
那么只需要扫描一棵B+树,避免了回表,这就叫覆盖索引。
所以覆盖索引的使用,一般是在需要查询主键的情况下。

最左前缀

组合索引的最左匹配原则。
多列值组成一个索引,专门用于组合搜索,即为组合索引。
比如表有列 id, name, age , address,发现大多数需求都是通过name和age来进行查询的,那么可以建立 name,age 的组合索引。
组合索引有顺序的区别,如果name在前,那么只有name匹配到了值,才会去匹配age;如果name不存在,那么age就不会参与匹配了。此为最左匹配原则。

索引下推

参考:https://www.jianshu.com/p/bdc9e57ccf8b
比如表有列 id, name, age , address
如要查询 select * from table where name = “jack” and age = 10;
假设表中有多条 name = "jack"的记录。
会根据联合索引(name,age)找到所有name = “jack” 的记录的主键,然后再根据主键回表查询age = 10的数据。
而索引下推会先根据联合索引找到 name = "jack"的索引,再筛选出age = 10 的索引,再回表查询全行数据。
明显地,索引下推减少了全行查询的量。

索引维护

索引在插入新的值的时候,为了保证有序性,必须要维护,有以下三种情况:

  1. 插入的值比较大,几乎没有成本。
  2. 插入的是中间的某个值,需要移动后续的元素,空出位置。
  3. 如果插入的数据页满了,需要单独申请一个新的数据页,然后移动部分数据过去,叫做页分裂,此时性能也会受影响,除了页分裂外还有页合并。

因此,为了避免页分裂和合并,尽量使用自增主键作为索引。

MySQL架构

在这里插入图片描述

redo日志

在这里插入图片描述

  • 当发生数据修改的时候, innodb 引擎会先将记录写到 redo log 中,并更新内存,此时更新就算是完成了,同时 innodb 引擎会在合适的时机将记录操作到磁盘中
  • Redolog 是固定大小的,是循环写的过程
  • 有了 redolog 之后, innodb 就可以保证即使数据库发生异常重启,之前的记录也不会丢失,叫做 crash safe

redo日志保证了事务的持久性。

undo日志

  • Undo Log 是为了实现事务的原子性。
  • 在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方
    称为 Undo Log )。然后进行数据的修改。如果出现了错误或者用户执行了
    ROLLBACK 语句,系统可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态。
  • 注意: undo log 是逻辑日志,可以理解为:
    当 delete 一条记录时, undo log 中会记录一条对应的 insert 记录
    当 insert 一条记录时, undo log 中会记录一条对应的 delete 记录
    当 update 一条记录时,它记录一条对应相反的 update 记录

binlog —— 服务端的日志文件

  • Binlog 是 server 层 (是MySQL执行器执行的,而非InnoDB引擎)的日志,主要做 mysql 功能层面的事情
  • Binlog日志也叫做二进制日志,虽然它保存了数据却是以二进制的形式保存
  • Binlog日志是Mysql服务日志中的一种
  • Binlog记录所有数据库表结构变更(例如CREATE、ALTER TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。
  • Binlog不会记录SELECT和SHOW这类操作,因为这类操作对数据本身并没有修改,但你可以通过查询通用日志来查看MySQL执行过的所有语句。
  • Binlog与redolog的区别:
  1. redo 是 innodb 独有的, binlog 是所有引擎都可以使用的
  2. redo 是物理日志,记录的是在某个数据页上做了什么修改, binlog 是逻
    辑日志,记录的是这个语句的原始逻辑
  3. redo 是循环写的,空间会用完, binlog 是可以追加写的,不会覆盖之前
    的日志信息
  • Binlog 中会记录所有的逻辑,并且采用追加写的方式
  • Binlog 可以用来恢复数据
    一般在企业中数据库会有备份系统,可以定期执行备份,备份的周期可以自己设置
    恢复数据的过程:
  1. 找到最近一次的全量备份数据
  2. 从备份的时间点开始,将备份的 binlog 取出来,重放到要恢复的那个时

数据更新的流程

在这里插入图片描述
执行流程:

  1. 执行器先从引擎中找到数据,如果在内存中直接返回,如果不在内存中,查
    询后返回
  2. 执行器拿到数据之后会先修改数据,然后调用引擎接口重新写入数据
  3. 引擎将数据更新到内存,同时写数据到 redo 中,此时处于 prepare 阶段,并通知执行器执行完成,随时可以操作
  4. 执行器生成这个操作的 binlog
  5. 执行器调用引擎的事务提交接口,引擎把刚刚写完的 redo 改成 commit 状态,更新完成
发布了40 篇原创文章 · 获赞 1 · 访问量 1081

猜你喜欢

转载自blog.csdn.net/weixin_44495162/article/details/103841583
今日推荐