反向键索引研究

反向键索引(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,有效地减少应用并发时的争用,另一方面,多数情况下数据在堆表中是按照插入的顺序而存储在邻近的位置上,所以数据块在内存中被再次使用的可能性是比较大的。总的来说,大多数情况下反向键索引带来的性能收益往往小于其所花费的代价,应用范围偏窄,在特殊情况下可以灵活使用。



### 双向索引的定义与用法 双向索引并非标准数据库术语,但在某些上下文中可能指代一种特殊的索引形式,即能够在正向和反向上都快速检索数据的数据结构。这种概念通常可以映射到图数据库中的边索引或者倒排索引的一种变体。 #### **双向索引的定义** 双向索引是一种特殊的设计模式,它不仅支持从到值的快速查找(类似于传统索引),还支持从值回到的逆向查找。这使得双向索引在需要频繁进行双向关联查询的情况下非常有用。例如,在社交网络中,用户之间的关系可以通过双向索引来表示,从而加速好友推荐算法[^1]。 #### **双向索引的数据结构** 实现双向索引的核心在于构建一对互为镜像的关系表或哈希表。具体来说: - 使用两个独立的哈希表分别维护从到值以及从值回溯到的映射。 - 或者采用更复杂的数据结构如双端链表结合散列表的形式来减少冗余存储开销。 下面是一个简单的伪代码示例展示如何利用双重哈希表创建一个基础版的双向索引系统: ```python class BiDirectionalIndex: def __init__(self): self.key_to_value = {} self.value_to_key = {} def add(self, key, value): if key not in self.key_to_value and value not in self.value_to_key: self.key_to_value[key] = value self.value_to_key[value] = key def get_by_key(self, key): return self.key_to_value.get(key) def get_by_value(self, value): return self.value_to_key.get(value) # Example Usage index = BiDirectionalIndex() index.add("Alice", "Bob") print(index.get_by_key("Alice")) # Output: Bob print(index.get_by_value("Bob")) # Output: Alice ``` 以上例子简单明了地展现了双向索引的工作机制——既可以从名字找到朋友也可以反过来做同样的事情[^2]. #### **双向索引的实际应用场景** 1. **社交网络**: 用户之间的好友关系管理非常适合应用此类技术因为经常涉及到双方互动的信息交换需求. 2. **搜索引擎优化(SEO)**: 当网站管理员试图提高特定关词排名时可能会考虑设置内部链接策略形成自然形成的双向引用链条有助于提升页面权重得分. 3. **生物信息学领域**, 特别是在基因组研究当中经常会遇到配对读取(pair-end reads)的情况此时就需要依靠类似的逻辑处理大量短片段DNA序列拼接任务. #### **注意事项** 虽然双向索引提供了极大的便利性但也伴随着额外的空间成本因此应当谨慎评估是否真的有必要引入这样复杂的解决方案考虑到整体系统的资源消耗情况做出合理决策[^4]. --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值