B+Tree--Mysql在插入(删除)是,节点(页)内有多个索引key,新索引key是怎么与其他key进行比较的呢?
插入操作(先插入,再分裂)
-
查找插入位置:从根节点开始,将新的索引键与当前节点内的键进行比较。如果新键小于当前节点的第一个键,则它应该插入到当前节点的最左边;如果新键大于当前节点的最后一个键,则它应该插入到当前节点的最右边;如果新键介于当前节点的两个键之间,则它应该插入到这两个键之间的位置。
-
新索引key最坏情况是否是与节点中一半+1的key进行就比较才能确定插入位置,或者有什么其他的算法,直接依靠节点内部的下标来直接插入(因为节点内都是连续的地址空间,为什么连续去搜mysql的按页存储)?所以B+Tree非叶子节点内部的索引key是以什么结构组织的?
-
非叶子节点的结构
-
索引key数组:
- 非叶子节点中的索引key数组是有序的,这使得在搜索操作时可以通过二分查找等高效的算法快速定位到目标key所在的子树。
-
指针数组:
- 与索引key数组相对应的是指针数组,指针数组中的每个指针指向子节点或者数据记录。指针的数量比索引key的数量多1,因为每个索引key都有两个子节点(除了根节点和叶子节点)。
- 索引key和指针通常是交替存储的,节点的两端通常是指针,指向子节点或者数据记录
-
在这个例子中,索引key数组中的元素是有序的,指针数组中的每个指针指向一个子节点或者数据记录。当进行搜索操作时,如果目标key小于10,则沿着p1指针继续搜索;如果目标key在10和20之间,则沿着p2指针继续搜索,以此类推
示例
例如,一个非叶子节点可能包含以下索引key和指针:
-
-
索引key: [10, 20, 30] 指针: [p1, p2, p3, p4]
-
-
还是没有清楚B+Tree如果插入一个索引Key到非叶子节点内部或者插入到叶子节点是怎么做的?
-
既然一个节点能存储的索引key是有限的,那就说明索引key的大小影响了一个节点能存多少索引key,听着好像和ken-len有关系,索引key如果比较大,影响节点存储key的数量,应该会影响层数,但B+tree不是层数(高度)可控吗?
-
不同的数据类型在计算
key_len
时占用的字节数不同。例如,int
类型通常占用4个字节,如果该列允许为空,则在4个字节的基础上加1个字节,即key_len
为5个字节,如果索引key是一个较长的字符串,那么key_len
会相应增加。例如,一个varchar(10)
类型的列,在utf8
编码下且不允许为空时,key_len
为10 * 3+2 = 32
字节。 -
B+Tree的节点大小是有限制的,通常为一个内存页的大小(如4KB或8KB等)mysql是16KB,
key_len
的大小会影响每个节点能够存储的索引key的数量。如果key_len
较大,那么每个节点能够存储的索引key数量就会减少,可能会导致树的高度增加,从而影响查询性能。
-
-
key_len
的大小会影响到每个叶子节点能够存储的索引key - 数据指针对的数量。在检索索引key时,也需要根据key_len
来确定读取的字节数,以正确解析出索引key的值。B+Tree索引key存储的是什么,被索引字段值的哈希码吗?,为什么还要解析索引key的值?-
、答:在B+Tree索引中,索引key存储的是被索引字段的值(所以字段的数据类型会影响索引key的大小),而不是哈希码。
-
数据值本身:在B+Tree索引中,非叶子节点存储的是索引key,这些key是被索引字段的值。例如,在一个以学生学号为索引的B+Tree中,非叶子节点存储的就是学号的值,这些值是按照一定的顺序排列的,用于引导搜索到对应的叶子节点子树。叶子节点存储的也是索引key(学号)以及对应的学生数据记录。
-
不是哈希码的原因:哈希码是通过哈希函数对数据进行处理得到的固定长度的摘要值,主要用于快速查找和比较。而B+Tree索引的目的是为了支持范围查询、排序查询等操作,存储被索引字段的值本身可以方便地进行这些操作。如果存储的是哈希码,虽然可以快速定位到某个具体的值,但难以进行范围查询和排序查询,因为哈希码本身并不反映数据的顺序关系
-
-
-
节点分裂:如果插入新键后,节点内的键数量超过了节点的最大容量,则需要进行节点分裂。通常,会将节点内的键分成两部分,中间的键会被提升到父节点中,而新键和剩余的键会被分配到两个新的子节点中。
删除操作(先删除,再借键)
-
查找删除位置:与插入操作类似,从根节点开始,将待删除的键与当前节点内的键进行比较,以找到它在树中的位置。
-
节点合并或借键:如果删除键后,节点内的键数量低于节点的最小容量,则可能需要进行节点合并或从相邻节点借键。如果相邻节点有多余的键,则可以从相邻节点借一个键来维持节点的最小容量;如果相邻节点也没有多余的键,则可能需要将当前节点和相邻节点合并成一个新的节点。