反向索引的定义

反向索引作为B-tree索引的一个分支,主要是在创建索引时,针对索引列的索引键值进行字节反转,进而实现分散存放到不同叶子节点块的目的。

反向索引针对的问题

  • 使用传统的B-tree索引,当索引的列是按顺序产生时,相应的索引键值会基本分布在同一个叶块中。当用户对该列进行操作时,难免会发生索引块的争用。
  • 使用反向索引,将索引列的键值进行反转,实现顺序的键值分散到不同的叶块中,从而减少索引块的争用。
  • 例如:键值1001、1002、1003,反转后1001、2001、3001,进而分散到不用的叶子节点块中。

反向索引应用场景

  1. 索引块成为热点块
  2. rac环境 :
    • rac环境下中多节点访问访问数据呈现密集且集中的特点,索引热块的产生较高。
    • 在范围检索不高的rac环境中使用反向索引可有效提高性能。

反向索引的优点与缺点

  • 优点:降低索引叶子块的争用问题,提升系统性能。
  • 缺点:对于范围检索,例如:between,>,<时,反向索引无法引用,进而导致全表扫面的产生,降低系统性能。

反向索引示例说明

  1. -- 创建两张相同结构的表,内部结构及数据均引用scott用户下的emp
  2. SQL> select count(*) from test01;
  3. COUNT(*)
  4. ----------
  5. SQL> select count(*) from test02;
  6. COUNT(*)
  7. ----------
  1. --针对表TEST01empno列,添加B-tree索引
  2. SQL> create index PK_TEST01 on TEST01(EMPNO);
  3. Index created.
  4. --针对表TEST02empno列,添加反向索引
  5. SQL> create index PK_REV_TEST02 on TEST02(EMPNO) REVERSE;
  6. Index created.
  7. --验证上面的索引,NORMAL/REV表明为反向索引
  8. SQL> select TABLE_NAME,INDEX_NAME,INDEX_TYPE from user_indexes where INDEX_NAME like '%TEST%';
  9. TABLE_NAME INDEX_NAME INDEX_TYPE
  10. -------------------- -------------------- --------------------
  11. TEST01 PK_TEST01 NORMAL
  12. TEST02 PK_REV_TEST02 NORMAL/REV
  1. --打开会话追踪
  2. SQL> set autotrace traceonly
  3. --相同条件查询,观察两表的执行计划
  4. SQL> select * from TEST01 where empno=7369;
  5. Execution Plan
  6. ----------------------------------------------------------
  7. Plan hash value: 515586510
  8. -----------------------------------------------------------------------------------------
  9. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  10. -----------------------------------------------------------------------------------------
  11. | 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
  12. | 1 | TABLE ACCESS BY INDEX ROWID| TEST01 | 1 | 87 | 2 (0)| 00:00:01 |
  13. |* 2 | INDEX RANGE SCAN | PK_TEST01 | 1 | | 1 (0)| 00:00:01 |
  14. -----------------------------------------------------------------------------------------
  15. Predicate Information (identified by operation id):
  16. ---------------------------------------------------
  17. - access("EMPNO"=7369)
  18. Note
  19. -----
  20. - dynamic sampling used for this statement (level=2)
  21. Statistics
  22. ----------------------------------------------------------
  23. recursive calls
  24. db block gets
  25. consistent gets
  26. physical reads
  27. redo size
  28. bytes sent via SQL*Net to client
  29. bytes received via SQL*Net from client
  30. SQL*Net roundtrips to/from client
  31. sorts (memory)
  32. sorts (disk)
  33. rows processed
  34. SQL> select * from TEST02 where empno=7369;
  35. Execution Plan
  36. ----------------------------------------------------------
  37. Plan hash value: 1053012716
  38. ---------------------------------------------------------------------------------------------
  39. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  40. ---------------------------------------------------------------------------------------------
  41. | 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
  42. | 1 | TABLE ACCESS BY INDEX ROWID| TEST02 | 1 | 87 | 2 (0)| 00:00:01 |
  43. |* 2 | INDEX RANGE SCAN | PK_REV_TEST02 | 1 | | 1 (0)| 00:00:01 |
  44. ---------------------------------------------------------------------------------------------
  45. Predicate Information (identified by operation id):
  46. ---------------------------------------------------
  47. - access("EMPNO"=7369)
  48. Note
  49. -----
  50. - dynamic sampling used for this statement (level=2)
  51. Statistics
  52. ----------------------------------------------------------
  53. recursive calls
  54. db block gets
  55. consistent gets
  56. physical reads
  57. redo size
  58. bytes sent via SQL*Net to client
  59. bytes received via SQL*Net from client
  60. SQL*Net roundtrips to/from client
  61. sorts (memory)
  62. sorts (disk)
  63. rows processed
  1. -- 相同范围条件查询,观察两表的执行计划
  2. SQL> select * from TEST01 where empno between 7350 and 7500;
  3. Execution Plan
  4. ----------------------------------------------------------
  5. Plan hash value: 515586510
  6. -----------------------------------------------------------------------------------------
  7. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  8. -----------------------------------------------------------------------------------------
  9. | 0 | SELECT STATEMENT | | 2 | 174 | 2 (0)| 00:00:01 |
  10. | 1 | TABLE ACCESS BY INDEX ROWID| TEST01 | 2 | 174 | 2 (0)| 00:00:01 |
  11. |* 2 | INDEX RANGE SCAN | PK_TEST01 | 2 | | 1 (0)| 00:00:01 |
  12. -----------------------------------------------------------------------------------------
  13. Predicate Information (identified by operation id):
  14. ---------------------------------------------------
  15. - access("EMPNO">=7350 AND "EMPNO"<=7500)
  16. Note
  17. -----
  18. - dynamic sampling used for this statement (level=2)
  19. Statistics
  20. ----------------------------------------------------------
  21. recursive calls
  22. db block gets
  23. consistent gets
  24. physical reads
  25. redo size
  26. bytes sent via SQL*Net to client
  27. bytes received via SQL*Net from client
  28. SQL*Net roundtrips to/from client
  29. sorts (memory)
  30. sorts (disk)
  31. rows processed
  32. SQL> select * from TEST02 where empno between 7350 and 7500;
  33. Execution Plan
  34. ----------------------------------------------------------
  35. Plan hash value: 3294238222
  36. ----------------------------------------------------------------------------
  37. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
  38. ----------------------------------------------------------------------------
  39. | 0 | SELECT STATEMENT | | 2 | 174 | 3 (0)| 00:00:01 |
  40. |* 1 | TABLE ACCESS FULL| TEST02 | 2 | 174 | 3 (0)| 00:00:01 |
  41. ----------------------------------------------------------------------------
  42. Predicate Information (identified by operation id):
  43. ---------------------------------------------------
  44. - filter("EMPNO">=7350 AND "EMPNO"<=7500)
  45. Note
  46. -----
  47. - dynamic sampling used for this statement (level=2)
  48. Statistics
  49. ----------------------------------------------------------
  50. recursive calls
  51. db block gets
  52. consistent gets0 redo size
  53. bytes sent via SQL*Net to client
  54. bytes received via SQL*Net from client
  55. SQL*Net roundtrips to/from client
  56. sorts (memory)
  57. sorts (disk)
  58. rows processed

通过上面的示例可以看到,当使用between条件进行范围查询时,采用反向索引的表,并没有使用索引,而是采用了全表扫面的方式进行检索。