反向键索引研究

反向键索引(Reverse Key Index)也是一种B树索引,但是它与一般的B树索引相比又有一个很奇特的地方。反向键索引将索引键值的每一个字节做一个翻转变换,举一个例子:数字123456在反向键索引中的存储形式便是654321。读到这里很多读者就会觉得匪夷所思,因为这会使得本来邻近的整数在索引中变得分散,比如123456、123457被翻转后分别是654321、754321,那么转换后的数字就不会作为邻近的数字存储,索引键的分布变得非常分散。

    由于在B树索引中经常要读取以及更新的数据往往被集中在一个特定的范围内,所以经常导致数据块的争用。特别是在Oracle Real Application Clusters环境中,比如一个实例正要往一个表中插入一个值为100的行,与此同时,另一个实例往这个表中插入一个值为101的行,两行数据及2个索引键极有可能是放在同一个数据块及索引叶块中的,两个实例对数据块以及索引叶块的争用便会对应用的并发造成影响。反向键索引在一定程度上可以很好的解决这一问题,反向键索引通过将索引键分散化,可以有效地减少索引叶块的争用。

    

SQL> create table test_reverse(id int,name char(10));
 
Table created.
 
SQL> insert into test_reverse values(123,'lex');
 
1 row created.
 
SQL> insert into test_reverse values(124,'tom');
 
1 row created.
 
SQL> insert into test_reverse values(125,'john');
 
1 row created.
 
SQL> commit;
 
Commit complete.
创建B树索引,dump索引块,查看索引列存储方式及顺序:

SQL> create index idx_test_reverse on test_reverse(id);
 
Index created.
 
SQL> set serveroutput on
SQL> exec seg_unused_space('IDX_TEST_REVERSE','INDEX','LEX');
total_blocks is 8
total_bytes is 65536
unused_blocks is 4
unused_bytes is 32768
last_used_extent_file_id is 4
last_used_extent_block_id is 5440
last_used_block is 4
 
PL/SQL procedure successfully completed.
 
SQL> alter system dump datafile 4 block 5443;
 
System altered.
row#0[8019] flag: ——, lock: 0, len=13
    col 0; len 3; (3): c2 02 18
    col 1; len 6; (6): 01 00 15 3f 00 00
    row#1[8006] flag: ——, lock: 0, len=13
    col 0; len 3; (3): c2 02 19
    col 1; len 6; (6): 01 00 15 3f 00 01
    row#2[7993] flag: ——, lock: 0, len=13
    col 0; len 3; (3): c2 02 1a
    col 1; len 6; (6): 01 00 15 3f 00 02

SQL> SELECT DUMP(123,16) DUMP FROM DUAL
  2  UNION ALL
  3  SELECT DUMP(124,16) FROM DUAL
  4  UNION ALL
  5  SELECT DUMP(125,16) FROM DUAL;
 
DUMP
--------------------
Typ=2 Len=3: c2,2,18
Typ=2 Len=3: c2,2,19
Typ=2 Len=3: c2,2,1a
在普通B树索引中,索引列的存放顺序为有序的123、124、125。那么在反向键索引中呢?

SQL> drop index idx_test_reverse;
 
Index dropped.
 
SQL> commit;
 
Commit complete.
 
SQL> create index reverse_test on test_reverse(id) reverse;
 
Index created.
 
SQL> alter system checkpoint;
 
System altered.
 
SQL> exec seg_unused_space('REVERSE_TEST','INDEX','LEX');
total_blocks is 8
total_bytes is 65536
unused_blocks is 4
unused_bytes is 32768
last_used_extent_file_id is 4
last_used_extent_block_id is 5440
last_used_block is 4
 
PL/SQL procedure successfully completed.
 
SQL> ALTER SYSTEM DUMP DATAFILE 4 BLOCK 5443;
 
System altered.
row#0[8019] flag: ——, lock: 2, len=13
col 0; len 3; (3): 18 02 c2
col 1; len 6; (6): 01 00 15 3f 00 00
row#1[8006] flag: ——, lock: 2, len=13
col 0; len 3; (3): 19 02 c2
col 1; len 6; (6): 01 00 15 3f 00 01
row#2[7993] flag: ——, lock: 2, len=13
col 0; len 3; (3): 1a 02 c2
col 1; len 6; (6): 01 00 15 3f 00 02

索引键值被翻转,顺序也发生了改变。

    很明显,反向键索引将索引键分散化也是有代价的,由于索引列的值不是连续的,所以无法进行索引范围扫描(INDEX RANGE SCAN),因为范围扫描中找到查询的第一个值后在进行下一个扫描时无法查找到满足条件的下一个值。

    查询示例:

SQL> select id from test_reverse where id=123 or id=124;
 
        ID
----------
       123
       124
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1306464222
 
----------------------------------------------------------------------------------
| Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |              |     2 |     8 |     1   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR  |              |       |       |            |          |
|*  2 |   INDEX RANGE SCAN| REVERSE_TEST |     2 |     8 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("ID"=123 OR "ID"=124)
 
 
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        456  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

本来应该进行的INDEX RANGE SCAN无法完成此查询,需以INLIST ITERATOR迭代方式进行,查询中有1个OR子句,所以需要对索引进行2次检索。
    反向键索引并不是一种被广泛使用的索引方式,主要适用于使用等值运算符“=”进行的查询。它的索引键值的分布是分散式的,并不是按照索引列的有序方式存储,因而无法进行范围化的查询。反向键索引的优势:一方面,它可以平衡I/O,有效地减少应用并发时的争用,另一方面,多数情况下数据在堆表中是按照插入的顺序而存储在邻近的位置上,所以数据块在内存中被再次使用的可能性是比较大的。总的来说,大多数情况下反向键索引带来的性能收益往往小于其所花费的代价,应用范围偏窄,在特殊情况下可以灵活使用。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值