带你彻底了解数据库索引

作者:Morven.Huang
来源: www.cnblogs.com/morvenhuang
一、引言
对数据库索引的关注从未淡出我们的讨论,那么数据库索引是什么样的?聚集索引与非聚集索引有什么不同?
希望本文对各位同仁有一定的帮助 。有不少存疑的地方,诚心希望各位不吝赐教指正,共同进步 。
二、B-Tree
我们常见的数据库系统,其索引使用的数据结构多是B-Tree或者B+Tree 。
例如,MsSql使用的是B+Tree,Oracle及Sysbase使用的是B-Tree 。所以在最开始,简单地介绍一下B-Tree 。
B-Tree不同于Binary Tree(二叉树,最多有两个子树),一棵M阶的B-Tree满足以下条件:
  • 每个结点至多有M个孩子;
  • 除根结点和叶结点外,其它每个结点至少有M/2个孩子;
  • 根结点至少有两个孩子(除非该树仅包含一个结点);
  • 所有叶结点在同一层,叶结点不包含任何关键字信息;
  • 有K个关键字的非叶结点恰好包含K+1个孩子;
另外,对于一个结点,其内部的关键字是从小到大排序的 。
以下是B-Tree(M=4)的样例:
带你彻底了解数据库索引

文章插图
 
对于每个结点,主要包含一个关键字数组Key[],一个指针数组(指向儿子)Son[] 。
【带你彻底了解数据库索引】在B-Tree内,查找的流程是:使用顺序查找(数组长度较短时)或折半查找方法查找Key[]数组,若找到关键字K,则返回该结点的地址及K在Key[]中的位置;
否则,可确定K在某个Key[i]和Key[i+1]之间,则从Son[i]所指的子结点继续查找,直到在某结点中查找成功;或直至找到叶结点且叶结点中的查找仍不成功时,查找过程失败 。
接着,我们使用以下图片演示如何生成B-Tree(M=4,依次插入1~6):
从图可见,当我们插入关键字4时,由于原结点已经满了,故进行分裂,基本按一半的原则进行分裂,然后取出中间的关键字2,升级(这里是成为根结点) 。
其它的依类推,就是这样一个大概的过程 。
带你彻底了解数据库索引

文章插图
 
三、数据库索引
1.什么是索引
在数据库中,索引的含义与日常意义上的“索引”一词并无多大区别(想想小时候查字典),它是用于提高数据库表数据访问速度的数据库对象 。
  • 索引可以避免全表扫描 。多数查询可以仅扫描少量索引页及数据页,而不是遍历所有数据页 。
  • 对于非聚集索引,有些查询甚至可以不访问数据页 。
  • 聚集索引可以避免数据插入操作集中于表的最后一个数据页 。
  • 一些情况下,索引还可用于避免排序操作 。
当然,众所周知,虽然索引可以提高查询速度,但是它们也会导致数据库系统更新数据的性能下降,因为大部分数据更新需要同时更新索引 。
2.索引的存储
一条索引记录中包含的基本信息包括:键值(即你定义索引时指定的所有字段的值)+逻辑指针(指向数据页或者另一索引页) 。
带你彻底了解数据库索引

文章插图
 
当你为一张空表创建索引时,数据库系统将为你分配一个索引页,该索引页在你插入数据前一直是空的 。此页此时既是根结点,也是叶结点 。
每当你往表中插入一行数据,数据库系统即向此根结点中插入一行索引记录 。当根结点满时,数据库系统大抵按以下步骤进行分裂:
  • 创建两个儿子结点
  • 将原根结点中的数据近似地拆成两半,分别写入新的两个儿子结点
  • 根结点中加上指向两个儿子结点的指针
通常状况下,由于索引记录仅包含索引字段值(以及4-9字节的指针),索引实体比真实的数据行要小许多,索引页相较数据页来说要密集许多 。
一个索引页可以存储数量更多的索引记录,这意味着在索引中查找时在I/O上占很大的优势,理解这一点有助于从本质上了解使用索引的优势 。
3.索引的类型
A)聚集索引,表数据按照索引的顺序来存储的 。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页 。
B)非聚集索引,表数据存储顺序与索引顺序无关 。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致 。
在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种 。


推荐阅读