版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载。转载时,请在文章明显位置注明原文链接。若在未经作者同意的情况下,将本文内容用于商业用途,将保留追究其法律责任的权利。如果有问题,请以邮箱方式联系作者(793113046@qq.com)。
一 反向索引
1.1 反向索引的定义
- 反向索引作为B-tree索引的一个分支,主要是在创建索引时,针对索引列的索引键值进行字节反转,进而实现分散存放到不同叶子节点块的目的。
1.2 反向索引针对的问题
- 使用传统的B-tree索引,当索引的列是按顺序产生时,相应的索引键值会基本分布在同一个叶块中。当用户对该列进行操作时,难免会发生索引块的争用。
- 使用反向索引,将索引列的键值进行反转,实现顺序的键值分散到不同的叶块中,从而减少索引块的争用。
- 例如:键值1001、1002、1003,反转后1001、2001、3001,进而分散到不用的叶子节点块中。
1.3 反向索引应用场景
- 索引块成为热点块
- rac环境
- rac环境下中多节点访问访问数据呈现密集且集中的特点,索引热块的产生较高。
- 在范围检索不高的rac环境中使用反向索引可有效提高性能。
1.4 反向索引的优点与缺点
- 优点:降低索引叶子块的争用问题,提升系统性能。
- 缺点:对于范围检索,例如:between,>,<时,反向索引无法引用,进而导致全表扫面的产生,降低系统性能。
1.5 反向索引示例说明
-
-- 创建两张相同结构的表,内部结构及数据均引用scott用户下的emp表
SQL> select count(*) from test01; COUNT(*) ---------- 14
SQL> select count(*) from test02; COUNT(*) ---------- 14 --针对表TEST01的empno列,添加B-tree索引 SQL> create index PK_TEST01 on TEST01(EMPNO); Index created.
--针对表TEST02的empno列,添加反向索引 SQL> create index PK_REV_TEST02 on TEST02(EMPNO) REVERSE; Index created.
--验证上面的索引,NORMAL/REV表明为反向索引 SQL> select TABLE_NAME,INDEX_NAME,INDEX_TYPE from user_indexes where INDEX_NAME like '%TEST%'; TABLE_NAME INDEX_NAME INDEX_TYPE -------------------- -------------------- -------------------- TEST01 PK_TEST01 NORMAL TEST02 PK_REV_TEST02 NORMAL/REV
--打开会话追踪 SQL> set autotrace traceonly
--相同条件查询,观察两表的执行计划 SQL> select * from TEST01 where empno=7369;
Execution Plan ---------------------------------------------------------- Plan hash value: 515586510 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST01 | 1 | 87 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_TEST01 | 1 | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPNO"=7369) Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 152 recursive calls 0 db block gets 23 consistent gets 0 physical reads 0 redo size 1025 bytes sent via SQL*Net to client 523 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> select * from TEST02 where empno=7369; Execution Plan ---------------------------------------------------------- Plan hash value: 1053012716 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST02 | 1 | 87 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_REV_TEST02 | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPNO"=7369) Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 148 recursive calls 0 db block gets 21 consistent gets 0 physical reads 0 redo size 1025 bytes sent via SQL*Net to client 523 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed -- 相同范围条件查询,观察两表的执行计划 SQL> select * from TEST01 where empno between 7350 and 7500; Execution Plan ---------------------------------------------------------- Plan hash value: 515586510 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 174 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST01 | 2 | 174 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_TEST01 | 2 | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPNO">=7350 AND "EMPNO"<=7500) Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 9 recursive calls 0 db block gets 10 consistent gets 0 physical reads 0 redo size 1120 bytes sent via SQL*Net to client 523 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2 rows processed SQL> select * from TEST02 where empno between 7350 and 7500; Execution Plan ---------------------------------------------------------- Plan hash value: 3294238222 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 174 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| TEST02 | 2 | 174 | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPNO">=7350 AND "EMPNO"<=7500) Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 5 recursive calls 0 db block gets 8 consistent gets0 redo size 1112 bytes sent via SQL*Net to client 523 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2 rows processed通过上面的示例可以看到,当使用between条件进行范围查询时,采用反向索引的表,并没有使用索引,而是采用了全表扫面的方式进行检索。