MySQL索引底层结构
MySQL索引底层结构
在索引优化之前,我们先要深入的了解一下索引底层的结构,理解索引的本质,方便我们后面优化索引。
1)索引本质
- 索引是帮助MySQL高效获取数据的 排好序的数据结构。
索引数据结构:
- 二叉树
- 红黑树
- Hash表
- B-Tree(主流)
如果没有索引的话,如何检索数据
select * from t1 where col2 = 22
执行以上的SQL,MySQL需要在数据库中一条一条数据从上往下去查询(每读取一次数据就会和磁盘做一次IO,读取还是随机读取磁盘),直到匹配到对应的数据,如果数据量多,过程极为耗费时间。
二叉树索引结构
一个节点只能有两个子节点
二叉树结构 左子节点的值小于父亲节点值,右子节点的值大于父亲节点的值,采用二分折半查找,速度较快
key:索引,value:索引在磁盘上所在行的磁盘地址
索引插入过程:
- 当前要插入20,走了第一步 发现20小于22,所以继续往左子节点走,到了第二步 发现比5大 比23小,到了第三步,发现比5大就插在了 右子节点。
MySQL二叉树查询逻辑:
- 比如下图,我们查询的值是91。MySQL会从第一个值判断,34 ,91比34大,就找右下角的分支继续比对。
- 91比89大,继续往89右下角的分支去查询,直到匹配到数据或者结构树查询一遍。
- 这样每次查询一次,都会和磁盘进行一次IO,但是比没有索引结构的效率明显高多了。
二叉树缺点
经典二叉树会出现一个极端例子,就是链表,节点数据越来越大。这种情况下,二叉树搜索性能就会降低
红黑树索引结构
红黑树又称 二叉平衡树,是在二叉树上升级来的,当你一边比另外一边树结构比较大的时候,就会自动做一个优化平衡调整。
但,红黑树不是最理想的选择,因为当数据量太大的时候,索引树的高度就会不可控,树形就会变得特别的高,假设有500W条数据,那你查询下来的时候,是从根节点依次往下比对,造成的磁盘IO也是很可怕的。
- 它的左子树和右子树都是一颗平衡二叉树。
- 它的左子树和右子树的高度之差(平衡因子)的绝对值不超过 1
索引插入过程:
- 我们插入1和2后,在插入3,他会自动平衡。
- 插入4和5后,红黑树又自己做了平衡调整。
Hash 索引结构
- 大多情况下,Hash索引效率比B+Tree更快
- Hash仅支持 ” = “、” IN “,不支持范围查询
- 哈希算法:除法散列,冲突机制采用 链表方式
Hash结构如何插入索引
- 插入 Alice,会对Alice进行Hash运算(除法散列),假设结果是2,然后就把Alice 存放到Hash桶 中 2 的位置
- 在2的后面按顺序 插入一个索引,索引data 指向 索引所在磁盘的文件地址
Hash结构如何查找数据
- 查找 ”Alice“,会对Alice进行Hash运算,假设结果是2
- 就去Hash桶 2的位置后,一一匹配索引,匹配到索引后根据 data的地址去硬盘中获取数据
B-Tree(B树)索引结构
所有的节点的数据索引都是从左到右递增排序。
所有索引数据都不重复。
所有的节点都会存放data磁盘地址。
B+Tree (B+树,B-Tree升级索引结构)
B+Tree分为2个块,叶子节点和非叶子节点,所有的节点的数据索引都是从左到右递增排序。
每一页左侧最小的索引都会作为冗余索引,放如 非叶子节点作为备份。
不论是单值索引还是联合索引,每个索引都会建立一颗自己的B+Tree。
主键索引结构(聚簇索引,密集索引)
聚簇索引的叶子节点会存放 主键ID的整行数据。
- 也就是说,只要在聚簇索引中找到索引的叶子节点,就可以直接找到该索引的整行数据。
叶子节点:
- 叶子节点拥有全部的索引字段。
- 叶子节点存放的data 其实是 磁盘地址,指向了该索引数据存放于 磁盘的地址
- 如果是二级索引,则存放的是 聚簇索引里面的主键ID地址
- 指向左右两边索引节点的 磁盘地址,该地址是为了快速找到 相近的 区间节点,这样做的目的是为了 提高区间访问的性能。
非叶子节点:
非叶子节点不存储data(磁盘地址)
只存储索引部分索引,它会从叶子节点的索引取出部分索引存于非叶子节点,目的是为了冗余备份索引,存放更多的索引
非主键索引结构
非主键索引结构又称为:二级索引,非聚集索引,稀疏索引
唯一索引,单值索引,联合索引,全文索引都属于 非主键索引
- 唯一索引:索引列的值必须唯一
- 全文索引:主要用来查找文本中的关键字,不是直接与索引值相比较,在插入索引时 会进行分词,MySQL分词器无法对中文分词且MySQL 全文索引性能一般,所以一般不用,如果需要全文检索建议使用elasticsearch
回表扫描和全表扫描的区别
回表扫描
- 通过辅助索引树找到聚簇索引的地址后,回表(聚簇索引) 继续查找主键索引。
全表扫描
- 通过 聚簇索引树 一行一行逐个扫描,因为聚簇索引树包含了整个表的数据。
非主键索引结构和主键索引结构的区别
- 非主键结构的叶子节点 data存储的是 聚簇索引的主键索引地址。
- 主键结构 叶子节点data存放的是 数据库表的整行详细数据。
目的:
避免数据的唯一性出问题
- 为了避免主键索引和非主键索引的data 数据出现数据不一致的情况
- 通过辅助索引树找到结果后,根据data的聚簇索引的主键索引地址 回表查询(回到聚簇索引树),读取整行数据。
- 为了避免主键索引和非主键索引的data 数据出现数据不一致的情况
节省存储空间
二级索引如何查找数据
- 去IDB文件(存放索引和数据的数据库文件)中,存放二级索引的数据文件中,按照二分查找的方式去查找,定位具体的数据后,该数据保存的 data ,存放的是主键索引。
- 拿着主键索引的地址去IDB中,找到主键索引(聚集索引)的结构文件,在通过 主键索引定位到具体的数据。
- 该行为也称为 回表。
查询的结果集都有索引
- 如果查询的结果集(select 的条件)都有索引,那么MySQL会默认走 二级索引(辅助索引),而不是走主键索引,因为主键索引是聚集索引,data里面放的是整行的数据,占用的空间大。
explain select * from film;
MMR(多范围磁盘读取)
二级索引读取到一条记录后,都需要携带主键索引,回表 去聚簇索引中查询。
二级索引存储的主键索引是无序的,每次回表的时候都要随机读取 聚簇索引Page页,直到成功为止,带来的IO开销很大,于是就引出了MMR,多范围磁盘读取。
MMR
- 先读取部分二级索引,从小到大排好序后,在统一回表。
- MMR触发条件较为苛刻,很少会使用到。
B+Tree如何查找数据
- 此时我们要查找数据30,MySQL会先从根节点开始查找,先把根节点所有元素拿到内存中(RAM),然后通过二分查找(折半查找)进行匹配,发现30比15大比56小,那30肯定就在这中间。
- 15和56之间存放的是 这一块的叶子节点信息的磁盘地址。
- MySQL拿到了这一块节点信息后,和第一步一样 存入内存中,再次进行 二分查找 ,后面轮到了20-30之间,在以此类推,直到找到30的索引,获取到该索引磁盘所在的磁盘地址,在通过该地址去磁盘中获取数据。
B+Tree节点存放大小
如图所示,在MySQL中一个节点也称为一页,Innodb数据库默认可存放16KB的索引(MySQL认可的最佳大小)。
- 该数字如果过大,数据都往内存丢,内存吃不消,过小的话会造成效率下降,所以默认16KB即可,不建议人为修改。
- 16KB大致能存放1170个索引,整颗B+Tree大致能放下几千万个索引。
show global status like 'innodb_page_size';
B-Tree和B+Tree的区别
核心概念:你的叶子结点横向能存放的索引越多,你的树高度就越小,检索数据就越快。
问题:为什么有B-Tree了为什么还要B+Tree?
区别一:节点索引存储空间问题
B树所有节点都存放了data,导致他每一页能存放的索引十分有限,B树的高度会变得很高,查询效率慢
- 假设每个索引占用1KB,那么一页只能存放16KB,那如果是千万级的数据,则他需要存放的树高度就有1250000,如果进行数据检索会耗费磁盘IO,还是很耗费时间的。
而如果把data存放在叶子节点,非叶子结点则存放索引,这样非叶子结点一页可以存放1170个索引,大大的缩小了树高度,数据进行检索的时候磁盘IO次数就变少了。
区别二:区间访问速度
B+Tree除了存放索引和磁盘地址外,还多了一个指向左右两边索引节点的 磁盘地址,该地址是为了快速找到 相近的 区间节点,这样做的目的是为了 提高区间访问的性能。
2)MyISAM存储引擎索引实现(非聚集索引)
- 存储引擎模式是基于表的,和数据库无关
- 所以一个数据库里面可以同时存储多个不同存储引擎的表
- MyISAM索引文件和数据文件是分开存储的,所以也叫 非聚集索引(非聚簇索引)
磁盘存储文件
MySQL的数据磁盘文件默认都是保存在在MySQL的安装目的底下,.frm 数据表结构信息文件 ,.MYD 数据文件, .MYI索引文件。
MyISAM如何进行数据查询
- MyISAM索引文件和数据文件是分离的(非聚集),所以将导致查询效率相对底下。
数据查询流程
- 如上图所示,我们查询Col1 = 50的话,它会从根节点进行二分查找,最终锁定了50这个叶子节点。
- 获取到他的data,它的data存储的是索引文件磁盘地址,通过该地址去磁盘文件myisam.MYI(索引文件) 中去查找,获取到索引存储数据的地址
- 通过索引存储数据的地址,去磁盘文件 myisam.MYD中 获取到真正索引存储的 数据文件,然后拿出来后再进行数据比对。
3)InnoDB存储引擎索引实现(聚集索引)
磁盘存储文件
MySQL的数据磁盘文件默认都是保存在在MySQL的安装目的底下,.frm 数据表结构信息文件,.idb 索引+数据库数据文件。
InnoDB索引实现
- 表数据文件(IBD) 是按照B+Tree组织的一个索引结构文件,包含了叶子节点(只存索引)和非叶子节点(存储 数据在磁盘的指针地址)
- 聚集索引,又称 聚簇索引,密集索引,叶子节点包含了 该索引 整行的数据记录。
- InnoDB表必须建立主键
- InnoDB表可以通过主键来 按照B+Tree 组织索引。
- 如果不创建主键
- MySQL会找到表中的 唯一索引(唯一性的二级辅助索引) 按照B+Tree 组织索引。
- 没有唯一索引
- 如果找不到的话,MySQL会自己创建一个 隐藏列(看不到的),来帮你维护一个 唯一索引。
- 创建主键
- 如果我们指定了主键,MySQL会通过该主键去按照B+Tree 组织索引。
- 推荐使用整型的自增主键
- 为什么推荐 整型
- 【效率问题】当MySQL从根节点开始查找数据时,索引是整型的明显比字符串(UUID等其他)比较的速度更快,效率更高
- 【空间问题】数据库的硬盘空间非常宝贵且硬盘价格昂贵,索引占用越小,越能节约磁盘空间,一页可以存放的索引越多。
- 为什么推荐 自增主键
- 区间访问速度、查找速度更快
- 叶子节点除了索引和磁盘地址外,还存放了一个左右两边 节点的地址,方便我们快速找到他相邻的节点。
- 如果我们是自增主键,那么叶子节点的索引则是有顺序,从小到大的排序。那么我们在进行范围查找,如:a > 20 and a < 50 ,我们找到了20的节点后,可以根据 他指向右边附近结点的地址,快速地定位到第三个节点(49,50)
- 避免索引移位
- 因为插入的时候是按顺序插入的,如果不是自增主键,插入其他类型的主键,很可能造成已有的索引进行移位,效率降低。
- 区间访问速度、查找速度更快
- 为什么推荐 整型
4)联合索引(复合索引)
- 多个字段共同组织成的索引。
- 生产环境中,一张表不建议添加多个单值索引,而是应当通过2-5个联合索引覆盖90%的SQL查询语句。
最左前缀原则
- 创建索引是按照 从左往右 创建的,查询数据的时候,自然也要 从左往右比较,且不可以跳过中间的字段。
- 每一页左侧最小的索引都会作为冗余索引,放如 非叶子节点作为备份。
为什么要强制使用 最左前缀原则
复合索引:mysql> KEY 'idx_name_age_position' (‘name’,'age','position') USING BTREE
走索引:mysql> explain select * from sys_order where name = 'Bill' and age = 30
不走索引:mysql> explain select * from sys_order where age = 30 and position = '2002-06-03'
- 如果查询的时候直接跳过了最左的索引(name),则直接使用后面的复合索引去查询(age),就会造成 走不了索引,然后只能全表扫描。
- 因为MySQL的索引都是排好序的,排序的时候是按照 复合索引的最左边的索引 进行排序的。
联合索引失效
- 查询的时候,跳过了 最左边第一个参数,违背了 最左原则
- 查询的时候,跳过了中间的参数,如:
- (‘name’,’age’,’position’)
- 查询的条件:where name = ‘aaa’ and position = ‘asdf’
- 跳过了age,这样的话 联合索引也会失效
- 查询的条件:where name = ‘aaa’ and position = ‘asdf’
- (‘name’,’age’,’position’)
5)自适应哈希索引
InnoDB会监控我们每颗索引树使用情况,如果发现某个索引经常被使用,那么就会在InnoDB内部创建一个 Hash 索引(自适应哈希索引),如果再次查询该索引,会通过Hash算法找到具体的记录,效率比去B+Tree查询更快。
自适应哈希索引特点
- 哈希算法:除法散列,冲突机制采用 链表方式
- 自适应哈希,我们是无法去干预的,只能InnoDB自己通过算法控制
- 哈希索引只会存 等值查询,如:where id = 1 ,非等值查询,如:范围查询是不会存入哈希索引
InnoDB引擎三大特性
双写缓冲区
自适应哈希索引
Buffer Pool
Hash结构如何插入索引
- 插入 Alice,会对Alice进行Hash运算,假设结果是2,然后就把Alice 存放到Hash桶 中 2 的位置
- 在2的后面按顺序 插入一个索引,索引data 指向 索引所在磁盘的文件地址
- 默认情况下,自适应索引一共有8个分区(最大可设置512个),目的是为了避免高并发下的数据库锁导致事务串行,执行效率低
Hash结构如何查找数据
- 查找 ”Alice“,会对Alice进行Hash运算,假设结果是2
- 就去Hash桶 2的位置后,一一匹配索引,匹配到索引后根据 data的地址去硬盘中获取数据
覆盖索引 / 索引覆盖
覆盖索引并不是一种索引,而是 一种索引的覆盖方式,可以直接从 辅助索引中可以得到查询的记录,不需要回表到聚簇索引查询。
不要使用select * ,而是应该 只查询你要的数据,并且你查询的字段进行能走索引。
7)三星索引
三星索引并不是真正的索引,有些类似于 覆盖索引一样,只是一种 规范设计。
三星索引优先级最高,一次查询通常只需要一次磁盘随机读取,以及一次索引扫描。
值得注意的是,由于三星索引条件和约束较为苛刻,如果在生产环境中,无法满足三星索引,请尽量满足二星索引。
一星:索引中查询相关的索引行是相邻的,或者至少相距足够靠近
二星(排序星):索引中数据列的顺序和查找中排序顺序相同
三星:索引中的列包含了查询中需要的全部列。索引包含查询所需要的数据列,不再进行全表查表,回表操作
下面举一个例子为大家介绍一下三星索引是什么样子的
现在有一张表,表结构如下
1 | CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL, `age` int(10) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
一星
我们现在给 age 加上索引
1 | create index idx_age on user (age); |
查询
1 | select * from user where age in (10,20,35,43) |
这条语句不一定符合一星,因为 age 是一个范围,数据可能比较分散
1 | select * from user where age = 20; |
这条语句是符合一星的,因为索引是按照 age 从小到大排序的,所以 age = 20 的数据肯定是在一起的
二星
1 | select * from user where age = 20 order by name; |
这条语句符合一星,但不符合二星,因为数据列的顺序是按照 age 排序的,如果现在改成 name 排序,可能导致索引顺序与 order by 排序结果不同,结果如下:
![img][image-9]
![img][image-10]
1 | select * from user where age = 20 order by age |
这条查询语句则符合一星和二星
三星
案例1:
1 | select * from user where age = 20 |
这条语句不符合三星,因为索引列中只有 id 和 age,没有 name
1 | select age from user where age = 20 |
这条语句则符合三星,因为只查询了 age,age 在索引中存在,不需要回表
案例2:满足三星索引
1 | CREATE TABLE customer ( |
查询SQL:
select cno,fname from customer where lname ='xx' and city ='yy' order by fname;
- 满足 最左前缀原则,也没有从 联合索引中间跳过
- 满足 一星要求
- 满足原因:lname 做第一个查询条件
- lname是大基数字段,重复率很低
- 满足 二星要求
- 满足原因:排序字段使用了索引,且 当前顺序是正常(按联合索引 最左匹配原则即可)
- 满足 三星要求
- 满足原因:select 提取的数据 都可以直接从索引中获取,不需要回表
索引使用注意事项
- 有多少个索引就会创建多少颗B+Tree,索引是帮助MySQL高效获取数据的 排好序的数据结构。方便我们快速查询到对应数据。
- 一个select 查询语句在执行过程中 一般最多只能使用一个索引,即便where条件存在多个索引。
- 特殊情况:特殊情况的话,会进行索引合并,具体可以看我博客 《MySQL索引合并详解》
索引产生的问题
空间上的代价:
- 索引并不是越多越好,需要我们权衡利弊
- 索引树是会占用存储空间的,创建一个索引就会创建一颗B+Tree,每一棵B+Tree的每一个节点都会占用16KB
- 一张表建议是创建2-5个索引,简直创建联合索引,少创建单值索引(利用率不高)
时间上的代价:
- 当我们对索引树进行增删改时,都可能会对节点和记录的排序造成破坏,存储引擎需要额外的时间来重新移位 保证排序正常。
[image-1]: https://image.javaxing.com/document/image-23310112203903416.png
[image-2]: https://image.javaxing.com/document/image-33113201114420.png
[image-3]: https://image.javaxing.com/document/image-23314130737114.png
[image-4]: https://image.javaxing.com/document/image-23114175148129.png
[image-5]: https://image.javaxing.com/document/image-233112211831540.png
[image-6]: https://image.javaxing.com/document/image-20230113140536198.png
[image-7]: https://image.javaxing.com/document/image-20230113194152318.png
[image-8]: https://image.javaxing.com/document/image-20230114123258928.png
[image-9]: https://image.javaxing.com/document/b84fe18e1826f37de612efcdfc834dc5.png
[image-10]: https://image.javaxing.com/document/77b4bfdb49030f1cbcc681fd6cff5ab6.png
[image-11]: https://image.javaxing.com/document/image-111012264736664.png
[image-12]: https://image.javaxing.com/document/image-22121219155836287.png
[image-13]: https://image.javaxing.com/document/image-32131219155931923.png
[image-14]: https://image.javaxing.com/document/image-311219161621525.png
[image-15]: https://image.javaxing.com/document/image-33121219162049481.png
[image-16]: https://image.javaxing.com/document/image-321911162031333.png
[image-17]: https://image.javaxing.com/document/image-444221219162108064.png
[image-18]: https://image.javaxing.com/document/image-3441219165700171.png
[image-19]: https://image.javaxing.com/document/image-911219174921322.png
[image-20]: https://image.javaxing.com/document/image-4411219180514043.png
[image-21]: https://image.javaxing.com/document/image-4411219181918341.png
[image-22]: https://image.javaxing.com/document/image-299811219184927038.png
[image-23]: https://image.javaxing.com/document/image-88811220111937589.png
[image-24]: https://image.javaxing.com/document/image-2211220113654078.png
[image-25]: https://image.javaxing.com/document/image-1121220121924390.png
[image-26]: https://image.javaxing.com/document/image-99121220122553923.png
[image-27]: https://image.javaxing.com/document/image-331114151128346.png
[image-28]: https://image.javaxing.com/document/image-1130114145450418.png
[image-29]: https://image.javaxing.com/document/image-33114155027132.png
[image-30]: https://image.javaxing.com/document/image-331114165702509.png
[image-31]: https://image.javaxing.com/document/image-99810114170357306.png
[image-32]: https://image.javaxing.com/document/image-441114170527627.png
[image-33]: https://image.javaxing.com/document/image-9787810114170849103.png
[image-34]: https://image.javaxing.com/document/image-20230114175148129.png
[image-35]: https://image.javaxing.com/document/image-3011314181641345.png
[image-36]: https://image.javaxing.com/document/image-9910115153639281.png
[image-37]: https://image.javaxing.com/document/image-44115154259643.png
[image-38]: https://image.javaxing.com/document/image-488115155720991.png
[image-39]: https://image.javaxing.com/document/image-3315160029398.png
[image-40]: https://image.javaxing.com/document/image-4990115160943828.png
[image-41]: https://image.javaxing.com/document/image-33115161057408.png
[image-42]: https://image.javaxing.com/document/image-120115161856260.png
[image-43]: https://image.javaxing.com/document/image-233115161922667.png
[image-44]: https://image.javaxing.com/document/image-2215162258406.png
[image-45]: https://image.javaxing.com/document/image-23021115214017903.png
[image-46]: https://image.javaxing.com/document/image-2333214336252.png
[image-47]: https://image.javaxing.com/document/image-33315214033832.png
[image-48]: https://image.javaxing.com/document/image-33315214048543.png
[image-49]: https://image.javaxing.com/document/image-11817211616275.png
[image-50]: https://image.javaxing.com/document/image-11123123123.png
[image-51]: https://image.javaxing.com/document/image-244118173305835.png
[image-52]: https://image.javaxing.com/document/image-49918173814120.png
[image-53]: https://image.javaxing.com/document/image-33118173857076.png
[image-54]: https://image.javaxing.com/document/image-330132400709.png
[image-55]: https://image.javaxing.com/document/image-2111110132311484.png
[image-56]: https://image.javaxing.com/document/image-23310155410153.png
[image-57]: https://image.javaxing.com/document/image-31555168354.png
[image-58]: https://image.javaxing.com/document/image-444118180938002.png
[image-59]: https://image.javaxing.com/document/image-88120181539569.png
[image-60]: https://image.javaxing.com/document/image-449121165001688.png
[image-61]: https://image.javaxing.com/document/image-2991121170345789.png
[image-62]: https://image.javaxing.com/document/image-988122112118536.png
[image-63]: https://image.javaxing.com/document/image-33188122143240681.png
[image-64]: https://image.javaxing.com/document/image-3388122143835659.png
[image-65]: https://image.javaxing.com/document/image-33188122143642313.png
[image-66]: https://image.javaxing.com/document/image-31880122144925633.png
[image-67]: https://image.javaxing.com/document/image-33122145512171.png
[image-68]: https://image.javaxing.com/document/image-203330122152318919.png
[image-69]: https://image.javaxing.com/document/image-2111122152357501.png
[image-70]: https://image.javaxing.com/document/image-28812153420540.png
[image-71]: https://image.javaxing.com/document/image-4491122155314394.png
[image-72]: https://image.javaxing.com/document/image-29878178781.png
[image-73]: https://image.javaxing.com/document/image-2878183103456906.png
[image-74]: https://image.javaxing.com/document/image-1278123104431894.png
[image-75]: https://image.javaxing.com/document/image-338781125190928371.png
[image-76]: https://image.javaxing.com/document/image-233113150503841.png
[image-77]: https://image.javaxing.com/document/image-2011123150536680.png
[image-78]: https://image.javaxing.com/document/image-23315104314926.png
[image-79]: https://image.javaxing.com/document/image-2035235741316.png
[image-80]: https://image.javaxing.com/document/image-23333175640577.png
[image-81]: https://image.javaxing.com/document/image-191881815947641.png
[image-82]: https://image.javaxing.com/document/image-998989717731.png
[image-83]: https://image.javaxing.com/document/image-2333131324773.png
[image-84]: https://image.javaxing.com/document/image-244123181753207.png
[image-85]: https://image.javaxing.com/document/image-444123182211535.png
[image-86]: https://image.javaxing.com/document/image-3313185933631.png
[image-87]: https://image.javaxing.com/document/image-244185949513.png
[image-88]: https://image.javaxing.com/document/%E6%9C%AA%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6.png
[image-89]: https://image.javaxing.com/document/image-4410124220437345.png
[image-90]: https://image.javaxing.com/document/image-244124220450050.png
[image-91]: https://image.javaxing.com/document/image-2441134421478.png
[image-92]: https://image.javaxing.com/document/image-3334318998.png
[image-93]: https://image.javaxing.com/document/image-44440230125135511348.png
[image-94]: https://image.javaxing.com/document/image-41182235133305.png
[image-95]: https://image.javaxing.com/document/image-233520661319.png
[image-96]: https://image.javaxing.com/document/image-233143136198.png
[image-97]: https://image.javaxing.com/document/image-23315155010029.png