Oracle 反向键索引的原理和用途(减少索引热点块)



我们知道Oracle会自动为表的主键列建立索引,这个默认的索引是普通的B-Tree索引。对于主键值是按顺序(递增或递减)加入的情况,默认的B-Tree索引并不理想。这是因为如果索引列的值具有严格顺序时,随着数据行的插入,索引树的层级增长很快。搜索索引发生的I/O读写次数和索引树的层级数成正比,也就是说,一棵具有5个层级的B -Tree索引,在最终读取到索引数据时最多可能发生多达5次I/O操作。因而,减少索引的层级数是索引性能调整的一个重要方法。

如果索引列的数据以严格的有序的方式插入,那么B-Tree索引树将变成一棵不对称的"歪树",如图 5所示:

而如果索引列的数据以随机值的方式插入,我们将得到一棵趋向对称的索引树,如图 6所示:

比较图 5和图 6,在图 5中搜索到A块需要进行5次I/O操作,而图 6仅需要3次I/O操作。
既然索引列数据从序列中获取,其有序性无法规避,但在建立索引时,Oracle允许对索引列的值进行反向,即预先对列值进行比特位的反向,如 1000,10001,10011,10111,1100经过反向后的值将是0001,1001,1101,0011。显然经过位反向处理的有序数据变得比较随机了,这样所得到的索引树就比较对称,从而提高表的查询性能。

1.反向索引应用场合
1)发现索引叶块成为热点块时使用
通常,使用数据时(常见于批量插入操作)都比较集中在一个连续的数据范围内,那么在使用正常的索引时就很容易发生索引叶子块过热的现象,严重时将会导致系统性能下降。
2)在RAC环境中使用
当RAC环境中几个节点访问数据的特点是集中和密集,索引热点块发生的几率就会很高。如果系统对范围检索要求不是很高的情况下可以考虑使用反向索引技术来提高系统的性能。因此该技术多见于RAC环境,它可以显著的降低索引块的争用。

2.使用反向索引的优点
最大的优点莫过于降低索引叶子块的争用,减少热点块,提高系统性能。

3.使用反向索引的缺点

使用反向键索引的最大的优点莫过于降低索引叶子块的争用,减少热点块,提高系统性能。由于反向键索引自身的特点,如果系统中经常使用范围扫描进行读取数据的话(例如在WHERE子句中使用“BETWEEN AND”语句或比较运算符“>”、“<”、“>=”、“<=”等),那么反向键索引将不适用,因为此时会出现大量的全表扫描的现象,反而会降低系统的性能。只有对反向键索引列进行“=”操作时,其反向键索引才会使用。

有时候可以通过改写sql语句来避免使用范围扫描,例如where id between 12345 and 12347,可以改写为where id in(12345,12346,12347),CBO会把这样的sql查询转换为where id=12345 or id=12346 or id=12347,这对反向索引也是有效的。
4.通过一个小实验简单演示一下反向索引的创建及修改

[sql] view plaincopy print?
  1. SQL> select count(*) from t1;
  2. COUNT(*)
  3. ----------
  4. 0
  5. SQL> select count(*) from t2;
  6. COUNT(*)
  7. ----------
  8. 0
  9. SQL> select count(*) from t3;
  10. COUNT(*)
  11. ----------
  12. 2000000
  13. SQL> select INDEX_NAME,INDEX_TYPE,TABLE_NAME from user_indexes;
  14. INDEX_NAME                     INDEX_TYPE                  TABLE_NAME
  15. ------------------------------ --------------------------- ------------------------------
  16. PK_T2                          NORMAL/REV                  T2
  17. PK_T1                          NORMAL                      T1

表t1是主键是正常的主键,表t2的主键是反向主键。现在我把表t3的数据分别插入到表t1和表t2

[sql] view plaincopy print?
  1. SQL> set timing on;
  2. SQL> set autotrace on;
  3. SQL> insert /* +append */ into t1 select * from t3;
  4. 已创建2000000行。
  5. 已用时间:  00: 01: 42.83
  6. 执行计划
  7. ----------------------------------------------------------
  8. Plan hash value: 4161002650
  9. ---------------------------------------------------------------------------------
  10. | Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  11. ---------------------------------------------------------------------------------
  12. |   0 | INSERT STATEMENT         |      |  2316K|   485M| 19014   (1)| 00:03:49 |
  13. |   1 |  LOAD TABLE CONVENTIONAL | T1   |       |       |            |          |
  14. |   2 |   TABLE ACCESS FULL      | T3   |  2316K|   485M| 19014   (1)| 00:03:49 |
  15. ---------------------------------------------------------------------------------
  16. Note
  17. -----
  18. - dynamic sampling used for this statement (level=2)
  19. 统计信息
  20. ----------------------------------------------------------
  21. 12305  recursive calls
  22. 538835  db block gets
  23. 203937  consistent gets
  24. 83057  physical reads
  25. 428323528  redo size
  26. 688  bytes sent via SQL*Net to client
  27. 614  bytes received via SQL*Net from client
  28. 3  SQL*Net roundtrips to/from client
  29. 2  sorts (memory)
  30. 0  sorts (disk)
  31. 2000000  rows processed
  32. SQL> commit;
  33. 提交完成。
  34. 已用时间:  00: 00: 00.04
  35. SQL> insert /* +append */ into t2 select * from t3;
  36. 已创建2000000行。
  37. 已用时间:  00: 02: 02.63
  38. 执行计划
  39. ----------------------------------------------------------
  40. Plan hash value: 4161002650
  41. ---------------------------------------------------------------------------------
  42. | Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  43. ---------------------------------------------------------------------------------
  44. |   0 | INSERT STATEMENT         |      |  2316K|   485M| 19014   (1)| 00:03:49 |
  45. |   1 |  LOAD TABLE CONVENTIONAL | T2   |       |       |            |          |
  46. |   2 |   TABLE ACCESS FULL      | T3   |  2316K|   485M| 19014   (1)| 00:03:49 |
  47. ---------------------------------------------------------------------------------
  48. Note
  49. -----
  50. - dynamic sampling used for this statement (level=2)
  51. 统计信息
  52. ----------------------------------------------------------
  53. 7936  recursive calls
  54. 6059147  db block gets
  55. 158053  consistent gets
  56. 56613  physical reads
  57. 790167468  redo size
  58. 689  bytes sent via SQL*Net to client
  59. 614  bytes received via SQL*Net from client
  60. 3  SQL*Net roundtrips to/from client
  61. 2  sorts (memory)
  62. 0  sorts (disk)
  63. 2000000  rows processed
  64. SQL> commit;
  65. 提交完成。
  66. 已用时间:  00: 00: 00.01

可以看见:由于反向索引的数据块比较分散了后,db block gets要稍微高一些。热块的争用有所缓解,consistent gets有所下降,从203937下降到158053,减少了45884次。redo size 也变多了!再来做查询,来看看他们的区别。

[sql] view plaincopy print?
  1. SQL> set autotrace traceonly;
  2. SQL> select OBJECT_NAME from t1 where id = 100;
  3. 已用时间:  00: 00: 00.06
  4. 执行计划
  5. ----------------------------------------------------------
  6. Plan hash value: 1141790563
  7. -------------------------------------------------------------------------------------
  8. | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
  9. -------------------------------------------------------------------------------------
  10. |   0 | SELECT STATEMENT            |       |     1 |    79 |     0   (0)| 00:00:01 |
  11. |   1 |  TABLE ACCESS BY INDEX ROWID| T1    |     1 |    79 |     0   (0)| 00:00:01 |
  12. |*  2 |   INDEX UNIQUE SCAN         | PK_T1 |     1 |       |     0   (0)| 00:00:01 |
  13. -------------------------------------------------------------------------------------
  14. Predicate Information (identified by operation id):
  15. ---------------------------------------------------
  16. 2 - access("ID"=100)
  17. 统计信息
  18. ----------------------------------------------------------
  19. 0  recursive calls
  20. 0  db block gets
  21. 4  consistent gets
  22. 3  physical reads
  23. 0  redo size
  24. 434  bytes sent via SQL*Net to client
  25. 416  bytes received via SQL*Net from client
  26. 2  SQL*Net roundtrips to/from client
  27. 0  sorts (memory)
  28. 0  sorts (disk)
  29. 1  rows processed
  30. SQL> select OBJECT_NAME from t1 where id > 100 and id < 200;
  31. 已选择99行。
  32. 已用时间:  00: 00: 01.10
  33. 执行计划
  34. ----------------------------------------------------------
  35. Plan hash value: 1249713949
  36. -------------------------------------------------------------------------------------
  37. | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
  38. -------------------------------------------------------------------------------------
  39. |   0 | SELECT STATEMENT            |       |    99 |  7821 |     1   (0)| 00:00:01 |
  40. |   1 |  TABLE ACCESS BY INDEX ROWID| T1    |    99 |  7821 |     1   (0)| 00:00:01 |
  41. |*  2 |   INDEX RANGE SCAN          | PK_T1 |    99 |       |     1   (0)| 00:00:01 |
  42. -------------------------------------------------------------------------------------
  43. Predicate Information (identified by operation id):
  44. ---------------------------------------------------
  45. 2 - access("ID">100 AND "ID"<200)
  46. Note
  47. -----
  48. - dynamic sampling used for this statement (level=2)
  49. 统计信息
  50. ----------------------------------------------------------
  51. 9  recursive calls
  52. 0  db block gets
  53. 140  consistent gets
  54. 189  physical reads
  55. 2356  redo size
  56. 2656  bytes sent via SQL*Net to client
  57. 482  bytes received via SQL*Net from client
  58. 8  SQL*Net roundtrips to/from client
  59. 0  sorts (memory)
  60. 0  sorts (disk)
  61. 99  rows processed
  62. SQL> select OBJECT_NAME from t2 where id = 100;
  63. 已用时间:  00: 00: 00.05
  64. 执行计划
  65. ----------------------------------------------------------
  66. Plan hash value: 1480579010
  67. -------------------------------------------------------------------------------------
  68. | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
  69. -------------------------------------------------------------------------------------
  70. |   0 | SELECT STATEMENT            |       |     1 |    79 |     0   (0)| 00:00:01 |
  71. |   1 |  TABLE ACCESS BY INDEX ROWID| T2    |     1 |    79 |     0   (0)| 00:00:01 |
  72. |*  2 |   INDEX UNIQUE SCAN         | PK_T2 |     1 |       |     0   (0)| 00:00:01 |
  73. -------------------------------------------------------------------------------------
  74. Predicate Information (identified by operation id):
  75. ---------------------------------------------------
  76. 2 - access("ID"=100)
  77. 统计信息
  78. ----------------------------------------------------------
  79. 1  recursive calls
  80. 0  db block gets
  81. 4  consistent gets
  82. 1  physical reads
  83. 0  redo size
  84. 434  bytes sent via SQL*Net to client
  85. 416  bytes received via SQL*Net from client
  86. 2  SQL*Net roundtrips to/from client
  87. 0  sorts (memory)
  88. 0  sorts (disk)
  89. 1  rows processed
  90. SQL> select OBJECT_NAME from t2 where id > 100 and id < 200;
  91. 已选择99行。
  92. 已用时间:  00: 00: 04.39
  93. 执行计划
  94. ----------------------------------------------------------
  95. Plan hash value: 1513984157
  96. --------------------------------------------------------------------------
  97. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  98. --------------------------------------------------------------------------
  99. |   0 | SELECT STATEMENT  |      |   336 | 26544 |  8282   (1)| 00:01:40 |
  100. |*  1 |  TABLE ACCESS FULL| T2   |   336 | 26544 |  8282   (1)| 00:01:40 |
  101. --------------------------------------------------------------------------
  102. Predicate Information (identified by operation id):
  103. ---------------------------------------------------
  104. 1 - filter("ID">100 AND "ID"<200)
  105. Note
  106. -----
  107. - dynamic sampling used for this statement (level=2)
  108. 统计信息
  109. ----------------------------------------------------------
  110. 29  recursive calls
  111. 1  db block gets
  112. 60187  consistent gets
  113. 30335  physical reads
  114. 5144  redo size
  115. 2656  bytes sent via SQL*Net to client
  116. 482  bytes received via SQL*Net from client
  117. 8  SQL*Net roundtrips to/from client
  118. 0  sorts (memory)
  119. 0  sorts (disk)
  120. 99  rows processed

可以看见,单个值查询的时候,表t1和表t2并无差别,但是范围查询的时候,表t1是INDEX RANGE SCAN,表t2是TABLE ACCESS FULL了。在数据库的优化中你经常会发现没有绝对的好,也没有绝对的差。

在考虑使用反向索引之前,大多数情况可以考虑对索引进行散列分区(hash)来减少索引叶块的争用。

反向索引:
 alter index id_inx rebuild reverse online;
 alter index id_inx rebuild online reverse;
 alter index name_inx rebuild online noreverse;



实验代码:

点击(此处)折叠或打开

  1. CREATE TABLE xt_revi_lhr AS SELECT * FROM dba_objects;
  2. CREATE INDEX REV_INDEX_lhr ON xt_revi_lhr(object_id) REVERSE;
  3. CREATE INDEX REV_INDEX_lhr2 ON xt_revi_lhr(UPPER(object_type)) REVERSE;
  4. CREATE INDEX REV_INDEX_lhr3 ON xt_revi_lhr(object_name) REVERSE;
  5. SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE '%/REV';
  6. UPDATE xt_revi_lhr t SET t.object_name='a';
  7. UPDATE xt_revi_lhr t SET t.object_name='b' WHERE ROWNUM<=1;
  8. SELECT * FROM xt_revi_lhr t WHERE t.object_id=100;
  9. SELECT * FROM xt_revi_lhr t WHERE t.object_id BETWEEN 100 AND 101;
  10. SELECT /*+index(t REV_INDEX_lhr)*/ * FROM xt_revi_lhr t WHERE t.object_id BETWEEN 100 AND 101;
  11. SELECT * FROM xt_revi_lhr t WHERE t.object_id <5;
  12. SELECT * FROM xt_revi_lhr t WHERE t.object_id >100000000;
  13. SELECT * FROM xt_revi_lhr t WHERE t.object_id <=5;
  14. SELECT * FROM xt_revi_lhr t WHERE t.object_id >=100000000;
  15. SELECT * FROM xt_revi_lhr t WHERE t.object_name='b';



About Me

...............................................................................................................................

● 本文整理自网络

● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文博客园地址:http://www.cnblogs.com/lhrbest

● 本文pdf版及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599     微信群:私聊

● 联系我请加QQ好友(646634621),注明添加缘由

● 于 2017-05-09 09:00 ~ 2017-05-30 22:00 在魔都完成

● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解

● 版权所有,欢迎分享本文,转载请保留出处

...............................................................................................................................

拿起手机使用微信客户端扫描下边的左边图片来关注小麦苗的微信公众号:xiaomaimiaolhr,扫描右边的二维码加入小麦苗的QQ群,学习最实用的数据库技术。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26736162/viewspace-2139025/,如需转载,请注明出处,否则将追究法律责任。

Oracle 反向键索引的原理和用途(减少索引热点块)相关推荐

  1. oracle 主键、唯一键值、唯一索引关系

    一般都认为一条数据在表中通过主键字段来唯一确定,但是有时候表中并不存在主键,但是重复数据插入也会报错,查看表结构发现,通过建立唯一键值也可以达到之一目的,但是最近有遇到数据库中没有唯一键.主键,重复数 ...

  2. mysql 字符串 底层_Mysql 的索引底层原理及数据结构详解

    Mysql 的索引底层原理 1.什么是索引? 索引是一种排好序的数据结构,mysql目前默认使用的是b+树. 2.为什么使用b+树? 例如表table 数据 id name 1 zs 2 ls 3 s ...

  3. Oracle外键需要建索引吗?

    关于Oracle中的外键,首先要说明一下. 1. 除非已定义了父表主键或唯一键约束,否则oracle将不允许创建子表的外键约束. 2. 在定义外键约束时,oracle不会自动创建索引,所以必须手动在与 ...

  4. oracle 主键_mysql 组合索引带主键ID的问题

    场景: mysql 5.7 某表 t_apply_info 上的2个索引,一个组合索引带了 主键字段 ID,另一个是同字段的单列索引 例如: KEY idx_1 (apply_serial_no,id ...

  5. oracle数据库建立主键约束,数据库-Oracle主键约束和唯一索引的黑与白

    1.  分别用两种方法创建主键 create table test1(id number,name varchar2(10)); insert into test1 values(1,'t1'); i ...

  6. SQL那些事儿(十)--oracle主键、唯一键与索引

    一般,我们看到术语"索引"和"键"交换使用,但实际上这两个是不同的.索引是存储在数据库中的一个物理结构,键纯粹是一个逻辑概念.键代表创建来实施业务规则的完整性约 ...

  7. oracle 主键 唯一性,oracle 唯一索引,唯一约束,主键之间的联系

    主键(primary key)是表中的一个或多个字段,它的值用于唯一地标识表中的某一条记录,在两个表的关系中,主键用来在一个表中引用来自于另一个表中的特定记录,,主键时一种唯一关键字,表定义的一部分. ...

  8. oracle主键 唯一索引的区别,Oracle 主键、唯一键与唯一索引的区别

    一般,我们看到术语"索引"和"键"交换使用,但实际上这两个是不同的.索引是存储在数据库中的一个物理结构,键纯粹是一个逻辑概念.键代表创建来实施业务规则的完整性约 ...

  9. oracle 主键约束重名,主键及主键索引的关系及相互影响

    主键的定义:列或多列的集合,用于唯一的标识表中的一行.一个表上只允许有一个主键. 我们在数据库中指定主键时,是通过主键约束来定义的.而创建主键约束时,又是需要有相应的索引来配合实现的.所以,本文的目的 ...

最新文章

  1. centos查看特定程序占用端口情况
  2. Seaborn在图像内自定义图例(legend)位置实战
  3. OpenMP并行化实例----Mandelbrot集合并行化计算
  4. python中系列的含义_一篇文章让你彻底搞清楚Python中self的含义
  5. NoSQL分布式数据库的独家见解- Adam Fowler
  6. c++获取sqlite3数据库表中所有字段的方法
  7. react 项目总结
  8. 腾讯云服务器CentOs7系统发布个人网站
  9. Helm 3 完整教程(八):Helm 函数讲解(2)字符串函数
  10. git本地仓库基本使用(Repository)
  11. [2018.10.10 T3] 三米诺
  12. 【免费软件测试视频-0022】——Winrunner系列之---GUI快速脚本向导
  13. GreenSock GSAP 3.0 最新版 所有内容创建于2020年4月4日
  14. 易福门流量计SA5000
  15. 网红护眼色——豆沙绿
  16. win7 设置电脑保护色
  17. 公司app上架正规要求需要办理icp许可证
  18. CAD编辑指南7:新建空白图纸和新建表格、导入图片
  19. 系统常用的通信对接方式
  20. Egret 2d 实现黑暗下光照效果

热门文章

  1. Android 音频开发——AudioRecord录音
  2. 疯狂的架构,BAT加华为、联想、新浪公司组织结构图一览
  3. springCloud 之 Hystrix 熔断器
  4. Unity Tutorial - Adventure Game
  5. telnet怎么算成功_男人一生怎么才算成功?
  6. 月亮代表我的心计算机谱子,月亮代表我的心
  7. vue 中使用 cesium
  8. 军工企业信息化与信息安全概要
  9. Scala学习笔记(三)
  10. php5apache2.dll,php5apache2_4.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家