Mysql热点问题总结
索引相关
为什么索引要存放到硬盘上?
数据库有两种存储介质。硬盘,内存。内存是临时存储,断电数据就会丢失。硬盘相当于永久存储介质,所以存储在硬盘上。
我们通过索引来查找数据的时候,需要计算磁盘 I/O 次数,磁盘 I/O 次数越多,越耗时。所以索引的数据结构,要尽量减少磁盘IO的操作次数。
索引数据结构?
平衡二叉树为什么不行?
我们知道,数据查询时间依赖磁盘 I/O 的次数。对于平衡二叉树来说,没访问一个节点,就需要进行一次磁盘 I/O 操作。虽然平衡二叉树比较的效率高,但是树的深度也同样高,这就意味着磁盘 I/O 操作次数多,会影响整体数据查询的效率。
B树?
上面我们知道,二叉树因为深度较高,到此磁盘I/O次数过多。影响查询效率。那B树是否可行。B树每个节点可以存储多个子节点,比如存有x个关键字,那个指针就有x+1个。这样的话,每个节点存储的多了,树的高度就相对二叉树矮。磁盘I/O次数就少,内存中比较次数变多(因为一个节点有多个数据)。不过内存比较的耗时相对磁盘I/O读取,可以忽略不计。
B+ 树
B+ 树基于 B 树做出了改进。
- 节点中有n个元素,就有n个子节点。B树是有N+1个子节点。
- 非叶子节点的关键字也会同时存在在子节点中,并且是在子节点中所有关键字的最大(或最小)。
- 非叶子节点仅用于索引,不保存数据记录,跟记录有关的信息都放在叶子节点中。而 B 树中,非叶子节点既保存索引,也保存数据记录。
- 所有关键字都在叶子节点出现,叶子节点构成一个有序链表,而且叶子节点本身按照关键字的大小从小到大顺序链接。
B+树与B树进行磁盘I/O的次数差不多,它们的根本差异在B+数的非叶子结点不存储数据,B树存储数据。这样做有哪些好处呢?
(1) 效率更加稳定。因为B+树的数据记录都存在叶子节点上,每次只有访问到叶子结点才能访问到数据。B树的数据节点上都有保存,可能有时候不用访问到叶子结点就可以查到数据。
(2) 查询效率更高。因为B+树的非叶子节点不保存数据,占用空间少,在同样大小内存上可以保存更多的关键字。树将变的更矮。
(3)在查询范围上,B+ 树的效率也比 B 树高。这是因为所有关键字都出现在 B+ 树的叶子节点中,并通过有序链表进行了链接。而在 B 树中则需要通过中序遍历才能完成查询范围的查找,效率要低很多。
hash索引
数组 + 链表。通过hash函数就算数组下标,根据数据下标快速定位到数据。
- 利用hash存储需要将所有的数据文件添加到内存,比较消耗内存空间。
- hash的查找是等值查询,速度很快,但是各个数据间没有范围规律,但在实际工作中更多的是范围查询,hash就不太合适了。
数据库与磁盘交互的基本单元:页
数据库对空间的管理,基本单位是页,连续接个页是区,多个区是段,多个段是表。
Innodb存储引擎中一页默认是16kb。页结构如下:
-
文件头
里面存储有两个指针,上一个文件指针,下一个文件指针。 -
页头
页的状态信息 -
最大最小记录
-
用户记录
就是我们数据表中记录的行记录。 -
空闲空间
还未使用的空间 -
页目录
记录用户记录的相对位置。可通过二分查找定位记录。
(1) 把所有记录分成几个组。包括最大,最小记录。
(2) 第一组只有最小记录的一条记录
(3) 最后一组包含最大记录,会有1-8条记录。
(3) 中间组会尽量平分数据,每组会有4-8条记录。
页目录中就存储的每一组的最后一条记录的位置偏移量。查询记录的时候,在页目录中先通过二分查找,然后去用户记录中查到对应记录。 -
文件尾
可以通过hash算法校验文件是否完整
页分裂
B+Tree中的叶子结点之间是通过双向链表关联起来的。
事务的隔离级别都是通过锁实现的。在InnoDB索引的设定中,要求主键索引是递增的,这样在构建索引树的时候才更加方便。假设你自定义了主键索引,而且你自定义的这个主键索引并不一定是自增的。那就有可能出现下面这种情况 如下图: