5.8.9 键压缩
用户利用键压缩(key compression)可以将索引或索引表(index-organized table)中键值(column value)的部分内容进行压缩,以便减少重复值带来的存储开销。
一般来说,索引的一个键(key)通常由两个片段(piece)构成:分组片段(grouping piece)及唯一片段(unique piece)。如果定义索引的键中不存在唯一片段,Oracle 会以 ROWID 的形式在此键的分组片段后添加一个唯一片段。键压缩(key compression)就是将键的分组片段从键中拆分出来单独存储,供多个唯一片段使用。
5.8.9.1 索引键的前缀和后缀
键压缩(key compression)将一个索引键拆分为前缀(prefix entry)(即分组片段(grouping piece))和后缀(suffix entry)(即唯一片段(unique piece))。压缩是通过一个索引块(index block)中的多个后缀共享一个前缀来实现的。在平衡树索引(B-tree index)中只有位于叶块(leaf block)的键会被压缩。在分支块(branch block)内不必存储键的后缀,因此其中的键也无需压缩。
键压缩(key compression)只能在每个索引块(index block)内分别实现,而不能跨多个索引块。压缩后每个索引行(index row)只保存后缀(suffix entry),而每个后缀将引用一个共享的前缀(prefix entry),后缀与其共享的前缀必须位于同一索引块内。
默认情况下,前缀(prefix entry)由除去最后一列之外的其他键列(key column)构成。例如,一个索引键(index key)由(column1,column2,column3)3 列构成,则默认的前缀为(column1, column2)。如一组索引值为(1,2,3),(1,2,4),(1,2,7),(1,3,5),(1,3,4),(1,4,4),则其中重复出现的前缀 (1,2),(1,3) 将被压缩。
用户也可以手工设定前缀长度(prefix length),即前缀所包含的列数。例如,如果用户设定前缀长度为 1,则在上述例子中,column1 为前缀,(column2,column3)为后缀,其中重复出现的前缀 1 将被压缩。
非唯一索引(nonunique index)的最大前缀长度(prefix length)为键列的个数,而唯一索引(unique index)的最大前缀长度为键列的个数减 1。
应用键压缩(key compression)后,生成索引时,如果一个键值(key value)的前缀(prefix entry)在索引块(index block)中不存在,此前缀才会被写入索引块中。一个前缀被写入后立即就可以被此索引块内的后缀(suffix entry)共享,直到所有引用此前缀的后缀都被删除为止。
5.8.9.2 性能上及存储上的考虑
键压缩(key compression)能够节约大量存储空间,因此用户可以在一个索引块(index block)内存储更多的索引键(index key),从而减少 I/O,提高性能。
键压缩(key compression)能够减少索引所需的存储空间,但索引扫描时需要重构(reconstruct)键值(key value),因此增加了 CPU 的负担。此外键压缩也会带来一些存储开销,每个前缀(prefix entry)需要 4 字节(byte)的管理开销。
5.8.9.3 使用键压缩
键压缩(key compression)在多种情况下都能够发挥作用,例如:
对于非唯一索引(nonunique index),Oracle 会在每个重复的索引键(index key)之后添加 rowid 以便区分。如果使用了键压缩,在一个索引块(index block)内,Oracle 只需将重复的索引键作为前缀((prefix entry))存储一次,并用各行的 rowid 作为后缀(suffix entry)。
唯一索引(nonunique index)中也存在相同的情况。例如唯一索引(stock_ticker,transaction_time)的含义是(项目,时间戳),通常数千条记录中stock_ticker 的值是相同的,但她们对应的 transaction_time 值各不相同。使用了键压缩后,一个索引块中每个 stock_ticker 值作为前缀只需存储一次,而各个transaction_time 值则作为后缀存储,并引用一个共享的 stock_ticker 前缀。
在一个包含 VARRAY 或 NESTED TABLE 数据类型(datatype)的索引表(index-organized table)中,这些collection 类型中各个元素(element)的对象标识符(object identifier)是重复的。用户可以使用键压缩以避免重复存储这些对象标识符。
有些情况无法使用键压缩(key compression)。例如,一个只有一个索引键(index key)的唯一索引(unique index)就无法使用键压缩,因为索引键中不存在可供共享的分组片段(grouping piece)。
5.8.10 逆序键索引
用户可以创建逆序键索引(reverse key index),此处的逆序指索引列值(index key value)得各个字节(byte)按倒序排列,而非索引列(index key)逆序排列。在 RAC 环境中,使用这样的排列方式可以避免由于对索引的修改集中在一小部分叶块(leaf block)上而造成的性能下降。通过使索引的键值逆序排列,可以使插入操作分布在索引的全部叶块中。
使用逆序键索引(reverse key index)后将无法对此索引进行索引区间扫描(index range scanning),因为在逆序键索引 中,词汇上(lexically)相邻的索引键(index key)在存储上未必相邻。因此在逆序键索引 上只能进行确定键扫描(fetch-by-key scan)或全索引扫描(full-index scan)。
有些情况下,使用逆序键索引(reverse key index)可以令 RAC 环境下的 OLTP 应用效率更高。例如,为一个 e-mail 应用中的所有邮件进行索引:由于用户可能保存旧的邮件,因此索引必须做到既能快速访问最新邮件,也能快速访