数据库索引(B树,B+树)

SQL查询提交给数据库系统的时候,一个查询优化器的软件模块将对查询进行非过程命令进行分析。这一章通过阐述查询如何利用数据库索引来提高访问表的数据的效率。

索引,与驻留在内存当中的数据结构有些类似。
目的是提高对表当中的行的数据的查找效率。

这些数据结构包括:二叉树,2-3树,散列表

数据库的索引包含的数据量比一次能够调入内存的数据量大。
所以数据库的索引的数据只能放在磁盘上,只有访问的时候才会被载入内存。这样做的好处是当计算机关闭的时候,内存的数据将会清空,但是索引将会驻留在磁盘上永久存在。

索引是什么?

索引是一系列存储在磁盘上的索引项组成。
索引有点像一个由两列组成的表。第一列是索引键,由行当中的某些列的值串联而成。第二列是行指针,指向行所在的磁盘的位置。

典型的通过索引查询是给定一个键或者键的范围,找到该键对应的索引项然后根据行指针找到相应的行。
数据库的索引通常是存放在磁盘上的和访问内存相比访问磁盘的速度是相当的慢的,数据库索引设计的重要目标就是减少读数据对于磁盘访问的次数。

分析一条查询语句输入时数据库系统做了什么

一个可以选择的方式是:执行一次表扫描,将不满足where子句当中的行进行剔除。
如果表当中的数据是非常少的那么直接扫描的方式将是非常快的,但是当表当中的行非常的多的时候通过索引来查询是非常有效的。

通过索引首先系统将通过索引找到对应的行指针,然后通过行指针直接读取所需的数据,这样从扫描整个表到只需要读取一定的索引然后直接读取对应数据的访问是大大的减少了的。

最终用户和提出查询的程序员不需要知道提高访问速度索引的存在

索引也就是空间换时间的一种方式。

  • 创建索引有create index语法
  • 索引项将按照索引键值的顺序存放在磁盘上
  • 索引键值的顺序可以是升序也可以是降序
  • 索引当中的内容将自动的随表当中的内容进行变化,如果表当中插入一行索引当中也会创建一条新的索引项然后将索引项放到正确的位置上。

索引键是为了更有效的查询数据。
二分查找算法对于查询内存当中已经排好序的键值而言是最有效的方法。但是对于基于磁盘的结构他就不是最有效的方法。

磁盘存储

基本表当中的行和索引是存储在磁盘上的,当他们被访问的时候将被读入内存。
数据库必须要保持持久性,所以磁盘是最合适的存储介质。
计算机内存是易失性存储器。
磁盘很便宜但是磁盘的访问非常的慢。所以磁盘需要使用数据库的索引结构。

一旦磁盘臂移动到正确的位置,不要只读一两个字节的数据,因为读取数据的时间相比于找到正确的位置来说延迟要小很多,所以一次性读取一个页面的数据是最划算的选择。

为什么不直接使用内存来进行数据访问呢

内存是不稳定的,当计算机因为某种原因崩溃内存当中修改过的数据将会丢失。具有事务性的数据库的一个要求就是当计算机崩溃的时候能够保证内存当中更新过的数据不会丢失。
这杯称为事务性恢复。

事务性恢复需要两个基本条件:
- 数据备份到非易失性介质上
- 恢复日志被记录到稳定的介质上

B树索引结构

和AVL树,2-3树等等的区别在于B树是存储在磁盘上的,只有需要访问的时候某些项才会被调入内存。
B树是当今数据库使用的最广泛的索引数据结构。
这里的B树是指B+树。

虽然我们可以证明二分查找是基于内存的有序索引的最有效的算法但是基于磁盘来说,二分查找可能需要更多的i/O操作。

分析:因为二分搜索每次只能读取一个比较结点的信息,最终比较多少次就需要从磁盘读取多少次。但是B树不一样,每次从磁盘的读取都是一读就读一个页面的大小2K,4k等等,这一个页面包含的索引项是很多的可能有256等等,读入一个页面之后在内存当中顺序的比较找到索引的合适位置这是内存操作是非常的快的,然后再读取下一个索引结点的指针,再读一个页面等等。。。整个100万行的数据只需要3次磁盘操作简直不要太快。

B树带来的不同就是每次读取的数据大量增多,比较的次数也显然增加但是这些比较都是在内存当中做的,带来的好处就是对于磁盘的读取操作极大的减少。
B树是稠密的二分查找树是稀疏的。

B树的构成

每个结点含有的域分为分隔符键值和结点指针
每个结点含有很多歌分隔符键值和结点指针。
一个结点占用的空间大小最大是一个页面的大小。
一次磁盘读取也就是读取一个结点。
可以通过计算得出需要多少个叶子结点页面。
从叶子结点的个数可以计算出上层所需要的结点的个数层层往上。

将索引结点保存在缓冲区当中还可以减少磁盘的访问。

B树的动态修改

当插入新的索引项的时候,B树是一种有效的自修改的结构。
当一个新的项被插入到磁盘上的有序列表上的时候,为了给新插入的索引项一个空的位置需要把后面的索引全部一次向后移动,这个移动的代价是非常的大的。
为了解决这样的问题:

B树每一层上的结点都不能是满的,相反每一层上的结点都必须预留一些空间,这样当进行插入操作的时候就不需要再申请新的空间。

当插入数据的时候,首先在表当中插入数据行,插入完毕之后,目录结构将引导新建的索引项到其合适的叶子结点当中,新建的项的插入操作总是发生在叶子层。但是有的时候叶子层已经太满了此时:将当前的叶子结点分裂成两个叶子结点,一个包含键值小的部分每一个包含键值大的部分,此时上层的索引结点需要修改加入新的分隔符合指向新建的叶子结点的指针,如果上层结点空间也不够就同样分裂层层向上,如果根结点也不够了此时也分裂再新建一个根结点,该节点指针指向原来的根节点分裂出来的两个结点。

这样就算要移动也只是移动一个页面当中的数据

B树的深度只有当分裂根节点的时候才会增加,根节点分裂之后所有叶子结点的深度都会增加1所以B树任然是平衡的。

B,B+树的属性

  • 每一个结点都是和磁盘页面大小一致并存放在磁盘的某个合适的位置
  • 叶子层以上的结点包含目录项 有n-1个分隔符和n个指向下一层结点的磁盘指针
  • 叶子层上的结点包含形式为keyval,rowid的项指向索引的行。
  • 根结点以下的,所有结点都至少是半满的
  • 根节点至少有两个项。

B树的深度近似为访问到叶子结点的IO操作次数
因为有内存缓冲区那些经常使用的B树上的上面几层的信息都放在缓冲区这样IO操作更少。

B+树是对B树的一种变形树,它与B树的差异在于:

有k个子结点的结点必然有k个关键码;
非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。

这里写图片描述

B和B+树的区别在于,B+树的非叶子结点只包含导航信息,不包含实际的值,
所有的叶子结点和相连的节点使用链表相连,便于区间查找和遍历。

  • 由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
  • B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值