目录
[3.1 什么是稠密索引?](#3.1 什么是稠密索引?)
[3.2 什么是稀疏索引?](#3.2 什么是稀疏索引?)
[4.1 索引的插入操作](#4.1 索引的插入操作)
[4.1 索引的删除操作](#4.1 索引的删除操作)
1、索引的基本概念
数据库中的索引与图书馆中书的索引作用相同,都是为了进行快速的查找。例如,为了根据指定的数据 ID 检索一条记录,数据库首先会去查找索引,找到相应记录所在的磁盘块,然后取出该磁盘块,最后得到该条指定的记录。//数据库索引用来加快数据的查询速度
通常,数据库有两种基本的索引类型:
- **顺序索引:**基于值的顺序排序。
- **散列索引:**基于将值平均分布到若干散列桶中,一个值所属的散列桶由散列函数( hash function)决定。
对于不同类型的索引,没有说哪一种类型的索引是绝对最好的,只能说某种类型的索引对特定的数据库是最适合的。每种类型索引都必须基于查找、插入、删除的时间以及空间的开销 (索引占据的存储空间)来进行综合评价。//评价索引需要考虑时间和空间等因素
使用索引需要占用额外的存储空间。不过占用额外空间的大小适度,那么牺牲一定的存储空间来换取性能的提高就是值得的。
本篇文章主要介绍顺序索引的相关概念,散列索引的相关内容将在后续的文章中进行探索。
2、顺序索引
顺序索引是指按顺序存储搜索码的值,并将每个搜索码与包含该搜索码的记录关联起来的索引。
所谓搜索码是指用于在文件中查找记录的属性或属性集。如果一个文件上有多个索引,那么它就有多个搜索码。//通俗的说就是表中的一个或多个字段
索引的原理就是把一条复杂的记录通过一小段信息进行标记,找到标记就找到了该条记录,从而节约查找时间,因此,怎么样去组织这样一小段信息,成了我们需要探讨的问题
如果包含记录的数据库文件按照某个搜索码指定的顺序进行排序,那么该搜索码对应的索引称为聚簇 索引(clustering index)。聚簇索引也称为主索引 ( primary index);//主索引通常建立在主键上,但并不一定要求唯一性,它也可以建立在其他非唯一列上
如果搜索码指定的顺序与数据库文件中记录的物理顺序不同,那么该搜索码对应的索引称为非聚簇索引 (nonclustering index)或辅助索引 (secondary index)。//非聚簇索引中一般索引与数据文件分开存放
聚簇索引和非聚簇索引在数据存储上的区别:
- 如果主索引是聚簇索引,那么表中的数据记录将按索引键的顺序进行物理存储。(查找一步到位)
- 如果主索引是非聚簇索引,索引和数据记录分开存储,索引项指向数据记录的存储位置。(需要多次查找)
总结: 聚簇索引的数据和索引存储在一个文件中, 它的叶子节点包含实际的数据记录本身,而不是指向数据记录的指针。这不同于非聚簇索引,非聚簇索引的叶子节点包含指向数据记录位置的指针。
一般可以使用的顺序索引有两类:稠密索引和稀疏索引。接下来,将详细介绍这两种索引。
3、稠密索引和稀疏索引
索引项或索引记录由一个搜索码值和指向具有该搜索码值的一条或者多条记录的指针构成。指向记录的指针包括磁盘块的标识和标识磁盘块内记录的块内偏移量 。//索引中存储的是数据存放的磁盘地址
++3.1 什么是稠密索引?++
在稠密聚集索引中,索引项包括搜索码值以及指向具有该搜索码值的第一条数据记录的指针 。具有相同搜索码值的其余记录顺序地存储在第一条数据记录之后 ,由于该索引是聚集索引,因此记录根据相同的搜索码值排序。//精确查找
在稠密非聚集索引中,索引必须存储的是指向所有具有相同搜索码值的记录的指针列表。下图为稠密索引示例:
//稠密索引其实就是为每一条记录都建立一个索引,然后通过该索引可以直接找到指定的记录,所谓的稠密就是密集的建立索引的意思,一对一的索引
++3.2 什么是稀疏索引?++
在稀疏索引中,只为搜索码的某些值建立索引项。只有当关系按搜索码排列顺序存储时才能使用稀疏索引,换句话说,只有索引是聚集索引时才能使用稀疏索引 。//范围查找
和稠密索引一样,每个索引项也包括一个搜索码值和指向具有该搜索码值的第一条数据记录的指针。为了定位一条记录,我们找到其最大搜索码值小于或等于所查找记录的搜索码值的索引项。然后从该索引项指向的记录开始,沿着文件中的指针查找,直到找到所需记录为止。下图为稀疏索引示例:
//稀疏索引顾名思义就是索引建的比较松散,索引与数据不是一一对应的。通过稀疏索引大致定位一个搜索范围,然后再从定位的范围当中进行查找,从而节省搜索量,因为涉及到范围查找,所以要求查找的数据必须有一定的顺序
比如一本字典,每页页眉都顺序地列出了该页中按字母序出现的第一个单词。字典中每页顶部的单词共同构成了字典页内容的稀疏索引。//就比如 A->B->C...这种顺序,其中 A、B、C就是稀疏索引
++有没有想过,为什么需要有这两种索引呢?++
这是因为我们在设计索引时,必须在存取时间和空间开销之间进行权衡。利用稠密索引通常可以比稀疏索引更快地定位一条记录。但是,稀疏索引也有比稠密索引优越的地方:它所占空间较小,并且插入和删除时所需的维护开销也较小。
比如,使用稀疏索引为每个数据块建立索引项是一个非常好的策略。原因在于,处理数据库查询的开销主要由把块从磁盘读到主存中的时间决定。一旦将块放入主存,扫描整个块的时间就是可以忽略的,只要记录不在溢出块中,就能使块的访问次数最小,同时能保持索引尽可能小(减少空间开销)。//使用稀疏索引定位包含所要查找记录的块,既减少了磁盘的I/O操作次数,又减少了索引的存储空间,这种方案在数据量非常大的时候具有优势
4、索引的更新
无论采用何种形式的索引,每当文件中有记录插入或删除时,索引都需要更新。索引更新可以设计为对旧记录的删除,以及随后对新记录的插入。因此,索引更新只需要考虑索引的插入 和删除,并不需要明确地考虑更新。
4.1 索引的插入操作
系统首先用待插人记录中的搜索码值进行查找,并根据索引是稠密索引还是稀疏索引而进行下一个操作。
++稠密索引的插入操作:++
如果该搜索码值不在索引中,系统就在索引中合适的位置插入具有该搜索码值的索引项。//新增索引项
否则进行如下操作:
- 如果索引项存储的是指向具有相同搜索码值的所有记录的指针,系统就在索引项中增加一个指向新记录的指针。//修改索引项
- 如果索引项存储一个仅指向具有相同搜索码值的第一条记录的指针 ,系统把待插入的记录放到具有相同搜索码值的其他记录之后。//不修改索引**项
++稀疏索引的插入操作:++
假设索引为每个块保存一个索引项。如果系统创建一个新的块,它会将新块中出现的第一个搜索码值插人到索引中。另一方面,如果这条新插入的记录含有块中的最小搜索码值,那么系统就更新指向该块的索引项;否则,系统对索引不做任何改动。//稀疏索引指向块,所以当插入记录不是边界值时,不需要去更改索引
++稠密索引指向具有相同搜索码值的第一条记录和指向具有相同搜索码值的所有记录的区别:++
举一个例子来说明,比如有一个学生表,按班级编号(ClassID)建立索引:
学号 (StudentID) | 姓名 (Name) | 班级编号 (ClassID) |
---|---|---|
1001 | Alice | 1 |
1002 | Bob | 1 |
1003 | Carol | 2 |
1004 | Dave | 2 |
1005 | Eve | 1 |
当稠密索引仅指向具有相同搜索码值的第一条记录时,索引会为每个唯一的搜索码值创建一个索引条目,但每个条目仅指向具有该值的第一条记录。这种方式的索引条目是唯一的,并且会依赖于数据记录的链表或块中的其他结构来访问所有具有相同搜索码值的记录。索引表如下:
ClassID | 指针 (Pointer) |
---|---|
1 | 指向(StudentID 1001) |
2 | 指向(StudentID 1003) |
数据记录之间的链表:
- StudentID 1001 -> StudentID 1002 -> StudentID 1005
- StudentID 1003 -> StudentID 1004
当稠密索引指向具有相同搜索码值的所有记录时,索引的每个条目指向的是一个数据结构,该结构包含所有具有该搜索码值的记录。这种方法意味着索引条目直接指向多个记录,而不是仅指向第一条记录。索引表如下:
ClassID | 指针 (Pointer) |
---|---|
1 | 指向(StudentID 1001, 1002, 1005) |
2 | 指向(StudentID 1003, 1004) |
这两种指向方式的区别在于:
当稠密索引仅指向第一条记录时,索引条目唯一,指向第一条记录。但需要通过链表或其他结构遍历所有记录。
当稠密索引指向所有记录时,索引条目包含所有记录的指针。可以直接访问所有相关记录,查询更高效,但索引空间开销更大。
//稠密索引并不是唯一索引,但是稠密索引与记录一一对应是一种比较好的设计,我们建立索引时也应该尽量去选择那些重复性不多的字段
4.1 索引的删除操作
删除一条记录,系统首先查找要删除的记录,然后下一步的操作也取决于索引是稠密索引还是稀疏索引。
++稠密索引的删除操作:++
如果被删除的记录是具有这个特定搜索码值的唯一的一条记录,系统就从索引中删除相
应的索引项。//删除整个索引项
否则采取如下操作:
- 如果索引项存储的是指向所有具有相同搜索码值的记录的指针,系统就从索引项中删除指向被删除记录的指针。//删除对应指针
- 否则,索引项存储的是指向具有该搜索码值的第一条记录的指针。在这种情况下,如果被删除的记录是具有该搜索码值的第一条记录,系统就更新索引项,使其指向下一条记录。
++稀疏索引的删除操作:++
如果索引不包含具有被删除记录搜索码值的索引项,则索引不必做任何修改。
否则系统采取如下操作:
- 如果被删除的记录是具有该搜索码值的唯一记录,系统用下一个搜索码值的索引记录替换相应的索引记录。如果下一个搜索码值已经有一个索引项,则删除而不是替换该索引项。
- 否则,如果该搜索码值的索引记录指向被删除的记录,系统就更新索引项,使其指向具有相同搜索码值的下一条记录。
//通过对稠密索引和稀疏索引的更新和删除操作,可以更好的了解这些索引的特征和数据组织形式
5、辅助索引
辅助索引必须是稠密索引,对每个搜索码值都有一个索引项,而且对文件中的每条记录都有一个指针。
辅助索引是数据库中除了主键(或聚簇索引)之外的额外索引,用于加快数据检索的速度。它们通常是基于表中的非唯一列或组合列构建的,允许数据库在执行查询时快速定位到符合条件的记录。
++为什么辅助索引不能是稀疏索引呢?++
我们知道稀疏索引可以只存储部分搜索码的值,然后通过顺序扫描文件的一部分,总是可以找到两个有索引项的搜索码值之间的搜索码值所对应的记录。如果辅助索引只存储部分搜索码值,两个有索引项的搜索码值之间的搜索码值所对应的记录可能存在于文件中的任何地方,并且通常只能通过扫描整个文件才能找到它们。//如果辅助索引为稀疏索引,那么通过辅助索引不能直接定位一条数据,也就失去了该索引的意义
辅助索引必须包含指向每一条记录的指针。我们可以用一个附加的间接指针层来实现非候选码的搜索码上的辅助索引。在这样的辅助索引中,指针并不直接指向文件,而是指向一个包含文件指针的桶。下图是一个辅助索引的结构,它在 instructor 文件的搜索码 salary 上使用了一个附加的间接指针层。
由于辅助码的顺序和物理码的顺序不同,因此如果我们想要按辅助码的顺序对文件进行顺序扫描,那么每读一条记录都很可能需要从磁盘读入一个新的块,这是很慢的。//因为数据库的数据一般都是按照聚簇索引进行排序的,所以不要使用辅助索引(非聚簇索引)进行范围查找
索引的自动生成
如果一个关系声明为有一个主码,大多数数据库实现会在主码上自动创建一个索引。只要一个元组插入到关系中,该索引就可以用来检查没有违反主码约束(即没有重复的主码值)。
辅助索引虽然能够提高使用聚集索引搜索码以外的码的查询性能,但是,辅助索引显著增加了数据库更新的开销。所以我们需要根据对查询和更新相对频率的估计来决定哪些辅助索引是需要的。
至此,全文结束。