
B+Tree 是 的变种,有着比 B-Tree 更高的查询性能,其相较于 B-Tree 有了如下的变化:
一般在系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 的基础上进行了优化,增加了顺序访问指针:
这种方式,遍历操作的时间复杂度是插入操作的平方,要做代码优化,那就和单向链表的正序访问一样,逆序访问就需要一个可以逆序移动的迭代器,即构成一个双向链表:在单向链表的每一个节点增加一个指针域,用于指向当前节点的前节点的位置。查询时如果一个点的凸包没有做出来就要接着查询它的左右儿子,由于每一层只有最后一个点的凸包还没被做出,靠左的区间顶多再找一层,最右边的区间满了但是凸包没做出来,因此还要一直向右找o(logn)个节点(左边的已经做出来了)直到叶子,因此查询的总复杂度为o(log^2n)。所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。
B-Tree 索引可以很好地用于单行、范围或者前缀扫描,他们只有在查找使用了索引的最左前缀(Leftmost Prefix)的时候才有用。不过 B-Tree 索引存在一些限制:
如果对多列进行索引(组合索引),列的顺序非常重要,mysql仅能对索引最左边的前缀进行有效的查找。在创建索引中对于相同的列,我们可能会按照不同的顺序来创建索引来满足不同的业务需求。也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢。
# 使用索引
A>5 AND A<10 - 最左前缀匹配
A=5 AND B>6 - 最左前缀匹配
A=5 AND B=6 AND C=7 - 全列匹配
A=5 AND B IN (2,3) AND C>5 - 最左前缀匹配,填坑
# 不能使用索引
B>5 - 没有包含最左前缀
B=6 AND C=7 - 没有包含最左前缀
# 使用部分索引
A>5 AND B=2 - 使用索引 A 列
A=5 AND B>6 AND C=2 - 使用索引的 A 和 B 列
如果大量的查询都基于在指定的部门或部门的雇员列表中查找人员,那么以列firstname、lastname和department这样的顺序来定义索引可能不如以department、firstname和lastname这样的顺序来定义索引好。尽量使用覆盖索引(只访问索引的查询(索引列或查询列一致)),减少select *。可以看到在join中的列全部是我们建立的多列索引的列,因此可以利用覆盖索引,当我们覆盖索引查找到需要的pro_id后,再关联表查询便可减少数据量。

# 使用索引排序
ORDER BY A - 最左前缀匹配
WHERE A=5 ORDER BY B,C - 最左前缀匹配
WHERE A=5 ORDER BY B DESC - 最左前缀匹配
WHERE A>5 ORDER BY A,B - 最左前缀匹配
# 不能使用索引排序
WHERE A=5 ORDER BY B DESC,C ASC - 升降序不一致
WHERE A=5 ORDER BY B,D - D 不在索引中
WHERE A=5 ORDER BY C - 没有包含最左前缀
WHERE A>5 ORDER BY B,C - 第一列是范围条件,无法使用 BC 排序
WHERE A=5 AND B IN(1, 2) ORDER BY C - B 也是范围条件,无法用 C 排序
B-Tree 这种索引方式是传统关系型中主要的索引构建方式,然而 BTree 通常会存在写操作吞吐量上的瓶颈,其需要大量的磁盘随机 IO,很显然,大量的磁盘随机 IO 会严重影响索引建立的速度。对于那些索引数据大的情况(例如,两个列的联合索引),插入速度是对性能影响的重要指标,而读取相对来说就比较少。譬如在一个无缓存的情况下,B-Tree 首先需要进行一次磁盘读写将磁盘页读取到内存中,然后进行修改,最后再进行一次 IO 写回到磁盘中。
# innodb使用一个缓冲池来保存索引和原始数据, 不像myisam.# 这里你设置越大,你在存取表里面数据时所需要的磁盘i/o越少.# 在一个独立使用的服务器上,你可以设置这个变量到服务器物理内存大小的80%# 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸.# 注意在32位系统上你每个进程可能被限制在 2-3.5g 用户层面内存限制,# 所以不要设置的太高.innodb_buffer_pool_size = 64m。根据上述分析,oceanbase把修改增量(包括增删改,下同)置于内存,每天在业务的相对低谷期再合并到基线数据中并释放内存(参见下篇:“错峰合并消除oceanbase每日合并对性能的影响”),从而使得oceanbase彻底消除了写事务的随机写磁盘,极大地提升了性能。举例来说,存取内存 (ram) 的速度较磁盘驱动器快非常多,所以我们可以将一部份的主存储器保留当成磁盘cache,每当有磁盘读取的需求时就把刚读取的数据拷贝一份放在cache内存中,如果系统继续要求读取或写入同一份数据或同一扇区 (sector) 时,系统可以直接从内存中的cache部分作读写的动作,这样系统对磁盘的存取速度感觉上会快许多。
LSM-tree 的主要思想是划分不同等级的树。以两级树为例,可以想象一份索引数据由两个树组成,一棵树存在于内存,一棵树存在于磁盘。内存中的树可以可以是 AVL Tree 等结构;因为数据大小是不同的,没必要牺牲 CPU 来达到最小的树高度。而存在于磁盘的树是一棵 B-Tree。
数据首先会插入到内存中的树。当内存中的树中的数据超过一定阈值时,会进行合并操作。合并操作会从左至右遍历内存中的树的叶子节点与磁盘中的树的叶子节点进行合并,当被合并的数据量达到磁盘的存储页的大小时,会将合并后的数据持久化到磁盘,同时更新父亲节点对叶子节点的指针。
所谓索引,即是快速定位与查找,那么索引的结构组织要尽量减少查找过程中磁盘i/o的存取次数(b+树相比b树,其非叶子节点占用更小的空间,可以有更多非叶子节点存放在再内存中,减少大量的io)。磁盘io次数,b-树(b类树)的特定就是每层节点数目非常多,层数很少,目的就是为了就少磁盘io次数,当查询数据的时候,最好的情况就是很快找到目标索引,然后读取数据,使用b+树就能很好的完成这个目的,但是b-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘io次数(磁盘io一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,io次数增多,一次io多耗时啊。就是说它是作为集群件的一个注册表的一个信息然后我们这个集群,各个节点之间,其实它是由两条网络进行搭建的,分别是外网还有内网外网是处理用户的需求的,也就是所有的用户的请求,统一是从外往这边进入的内网是集群节点之间的一个通信的一条通道多活集群,就是说它的每一个节点都是可读可写,可以同时读写在我们的集群中,我们刚才说过,我们有一条内网,它是用于处理数据在节点之间的传输在多个节点中,如果我想要获取的这个数据块已经在别的节点中了,那么我不需要将对应的数据块刷回到磁盘,我再从磁盘进行读取,而我的这种处理方式是直接通过内网将这个数据块传输过来这样就减少一个io的消耗这种技术,在我们称为一种缓存的融合技术也就是说,多个节点的这种内存,我们可以把它当成统一来处理实现缓存融合需解决问题第一, 多个节点有可能会同时共同读取数据块。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-107249-2.html