C++索引

1,047 阅读10分钟

基本概念

输入顺序文件( entry-sequenced file )

按照记录进入系统的顺序存储记录

  • 输入顺序文件相当于一个磁盘中未排序的线性表
  • 因此不支持高效率的检索

主码

主码( primary key ) 是数据库中的每条记录的唯一标识

  • 例如,公司职员信息的记录的主码可以是职 员的身份证号码
  • 如果只有主码,不便于各种灵活检索

辅码

  • 辅码( secondary key ) 是数据库中可以出现重复值的码
  • 辅码索引把一个辅码值与具有这个辅码值的每一条记录的主码值关联起来
    • 大多数检索都是利用辅码索引来完成的

索引

索引( indexing ) 是把一个关键码与它对应的数据记录的位置相关联的过程

  • (关键码,指针)对,即( key, pointer )
  • 指针指向主要数据库文件(即“主文件”)中的完整记录

索引文件( index file ) 是用于记录这种联系的文件组织结

  • 索引技术是组织大型数据库的一种重要技术
  • 高效率的检索
  • 插入、更新、删除

稠密索引 vs 稀疏索引

  • 稠密索引:对 每个记录建立一个索引项
    • 主文件不按照关键码的顺序排列
  • 稀疏索引:对一组 记录建立一个索引项
    • 记录按照关键码的顺序存放
    • 可以把记录分成多个组(块)
    • 索引指针指向的这一组记录在磁盘中的起始位置

线性索引

线性索引文件

  • 按照关键码的顺序进行排序
  • 文件中的指针指向存储在磁盘上的文件记录起始位置或者主索引中主码的起始位置

线性索引的问题

  • 线性索引太大,存储在磁盘中
    • 在一次检索过程中可能多次访问磁盘,从而影响检索的效率
    • 使用二级线性索引
  • 更新线性索引
    • 在数据库中插入或者删除记录时

二级线性索引

  • 例如,磁盘块的大小是 1024 字节,每对 (关键码,指针)索引对需要 8 个字节1024 / 8 = 128,每磁盘块可以存储 128 条这样的索引对
  • 假设数据文件包含 10000 条记录
    • 稠密一级线性索引中包含 10000 条记录, 10000/128 = 78.1
    • 那么一级线性索引占用 79 个磁盘块
  • 相应地,二级线性索引文件中有 79项索引对,这个二级线性索引文件可以在一个磁盘块

二级线性索引的例子

*关键码与相应磁盘块中第一条记录的关键码的值相同 指针指向相应磁盘块的起始位置

静态索引

  • 索引结构在文件创建、初始装入记录时生成
  • 一旦生成就固定下来,在系统运行(例如插入和删除记 录)过程中索引结构并不改变
  • 只有当文件再组织时才允许改变索引结构
  • 组织索引一般不用二叉树而采用多分树,大大减少访问外存的次数

ISAM

  • 基于多分树的 ISAM ( Index Sequential Access Method )
    • 为磁盘存取而设计
    • 结构采用多级索引
      • 主索引
      • 柱面索引
      • 磁道索引
  • 在采用基于 B+ 树的 VSAM ( Virtual Storage Access Method ) 技术之前,IBM 公司曾经 广泛地采用 ISAM 技术

倒排索引(Inverted Index)

  • 基于属性的倒排
    • 要求检索结构中某个或若干个属性满足一定条件的结点(不是按关键码的值检索)
    • 按照属性建立索引
  • 对正文文件的倒排
    • 以文中的词(word)为索引项建立的索引

基于属性的倒排

  • 对某属性按属性值建立索引表,称倒排表

  • “属性 – 指针”对 (attr, ptrList)

    • (属性值,具有该属性值的各记录指针)
    • 指针可以是关键码,或该记录的主文件地址
    • 为了高效地组织属性倒排索引表,可以对于每一个属性,对于其中的每一个属性值,都建立一个线性表,存放与此属性值相对应的所有记录的指针
  • 颠覆主文件的顺序,因而称为倒排索引

  • 属性往往是离散型的

    • 对于连续型的索引,往往用B树
  • 倒排文件:带有倒排索引的文件

优缺点

  • 优点:
    • 能够对于基于属性的检索进行较高效率的处 理
  • 缺点:
    • 花费了保存倒排表的存储代价
    • 降低了更新运算的效率

对正文文件的倒排

正文索引 (Text Indexing)处理的就是“建立一个数据结构以提供对文本内容的快速检索”

  • 方法
    • 词索引 ( word index )
    • 全文索引 ( full-text index )

词索引

  • 基本思想:
    • 把正文看作由符号和词所组成的集合,从正文中抽取出关键词,然后用这些关键词组成一些适合快速 检索的数据结构。
  • 适用于多种文本类型,特别是那些可以很容易 就解析成一组词的集合的文本
    • 适用于英文
    • 中文等东方文字要经过“切词”处理

全文索引

  • 基本思想:
    • 把正文看作一个长的字符串
    • 在数据结构中记录的是子字符串的开始位置
    • 查询就可以针对正文中的任何子字符串
  • 可以对每一个字符建立索引,从而使查询词不再限于关键词
  • 需要更大的空间

倒排文件使用最广泛的是词索引

  • 词索引使用最广泛
  • 一个已经排过序的关键词的列表,其中每个关键词指向一个倒排 (posting list)
    • 指向该关键词出现文档集合
    • 在文档中的位置

建立正文倒排文件

  1. 对文档集中的所有文件都进行分割处理, 把正文分成多条记录文档 切分正文记录取决于程序的需要 定长的块、段落、章节,甚至一组文档
  2. 给每条记录赋一组关键词 以人工或者自动的方式从记录中抽取关键词
    • 停用词( Stopword )
    • 抽词干( Stemming )
    • 切词(Segmentation)
  3. 建立正文倒排表、倒排文件,得到各个关键词的集合,对于每一个关键词得到其倒排表,然后把所有的倒排表存入文件

对关键词的检索

  1. 在倒排文件中检索关键词
  2. 如果找到了关键词,那么获取文件中的对应的倒排表,并获取倒排表中的记录
  • 通常使用另一个索引结构(字典)进一步对关键词表进行有效索引
  • Trie – 散列

倒排文件优劣

  • 高效检索,用于文本数据库系统
  • 支持的检索类型有限
    • 检索词有限(只能用索引文件中的关键词)
    • 倒排文件中的索引效率可能不高
    • 需要的空间代价往往很高

动态索引(B树,B+树)

单独列出,请点击上面链接

位索引技术

  • B 树适合于查找并取回少量记录的情况
  • 对于数据仓库的复杂交互式查询,B树有三个缺点:
    1. B 树对唯一值极少的(低基数)数据字段几乎毫无价值
    1. 在数据仓库中构造和维护索引的代价高
    1. 对于带有分组及聚合条件的复杂查询无能为力

例如有张表名为table的表,由三列组成,分别是姓名、性别和婚姻状况,其中性别只有男和女两项,婚姻状况由已婚、未婚、离婚这三项,该表共有100w个记录。现在有这样的查询: select * from table where Gender=‘男’ and Marital=“未婚”;

不使用索引

  不使用索引时,数据库只能一行行扫描所有记录,然后判断该记录是否满足查询条件。

B树索引

  对于性别,可取值的范围只有'男','女',并且男和女可能各站该表的50%的数据,这时添加B树索引还是需要取出一半的数据, 因此完全没有必要。相反,如果某个字段的取值范围很广,几乎没有重复,比如身份证号,此时使用B树索引较为合适。事实上,当取出的行数据占用表中大部分的数据时,即使添加了B树索引,数据库如oracle、mysql也不会使用B树索引,很有可能还是一行行全部扫描。

位图索引出马

如果用户查询的列的基数非常的小,即只有的几个固定值,如性别、婚姻状况、行政区等等。要为这些基数值比较小的列建索引,就需要建立位图索引。

对于性别这个列,位图索引形成两个向量,男向量为10100...,向量的每一位表示该行是否是男,如果是则位1,否为0,同理,女向量位01011。

对于婚姻状况这一列,位图索引生成三个向量,已婚为11000...,未婚为00100...,离婚为00010...。

当我们使用查询语句“select * from table where Gender=‘男’ and Marital=“未婚”;”的时候首先取出男向量10100...,然后取出未婚向量00100...,将两个向量做and操作,这时生成新向量00100...,可以发现第三位为1,表示该表的第三行数据就是我们需要查询的结果。

位图索引的适用条件

上面讲了,位图索引适合只有几个固定值的列,如性别、婚姻状况、行政区等等,而身份证号这种类型不适合用位图索引。   

此外,位图索引适合静态数据,而不适合索引频繁更新的列。举个例子,有这样一个字段busy,记录各个机器的繁忙与否,当机器忙碌时,busy为1,当机器不忙碌时,busy为0。

这个时候有人会说使用位图索引,因为busy只有两个值。好,我们使用位图索引索引busy字段!假设用户A使用update更新某个机器的busy值,比如update table set table.busy=1 where rowid=100;,但还没有commit,而用户B也使用update更新另一个机器的busy值,update table set table.busy=1 where rowid=12; 这个时候用户B怎么也更新不了,需要等待用户A commit。

原因:用户A更新了某个机器的busy值为1,会导致所有busy为1的机器的位图向量发生改变,因此数据库会将busy=1的所有行锁定,只有commit之后才解锁。

红黑树

单独列出,请点击上面链接

红黑树和B树应用场景有何不同

两者都是有序数据结构,可用作数据容器。

红黑树多用在内部排序,即全放在内存中的,微软STL的map和set的内部实现就是红黑树。

B树多用在内存里放不下,大部分数据存储在外存上时。因为B树层数少,因此可以确保每次操作,读取磁盘的次数尽可能的少。

在数据较小,可以完全放到内存中时,红黑树的时间复杂度比B树低。 反之,数据量较大,外存中占主要部分时,B树因其读磁盘次数少,而具有更快的速度。