设为首页 收藏本站
查看: 463|回复: 1

[经验分享] ORACLE B-TREE(B树)索引

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2013-12-23 09:41:48 | 显示全部楼层 |阅读模式
内容简介:
1.普通B-TREE 索引;
2.唯一B-TREE 索引;
3.复合索引;
ORACLE 默认的索引类型为B-TREE 索引,表中的行标识符(ROWID)和行相关的列值被存储在一个平衡树的树状结构的索引块中;使用B-TREE索引有以下几个原因:
? 提高SQL语句的性能;
? 强制执行主键和唯一键约束的唯一性;
? 减少通过主键和外键约束关联的父表和子表间潜在的锁定问题 ;
1.普通B-TREE 索引
在一张未建立任何索引的500万行人员信息表中根据人员ID查询人员信息
select id,name,gender,homeaddr from th01 where id=998698;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 16715 (1)| 00:03:21 |
|* 1 | TABLE ACCESS FULL| TH01 | 1 | 38 | 16715 (1)| 00:03:21 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=998698)
Statistics
----------------------------------------------------------
61222 consistent gets
61208 physical reads
通过观察执行计划,CBO优化器执行了全表扫描,一致读取61222个块,61208个物理读,基于性能的考虑和表结构的分析,为其B-TREE索引:
SQL> CREATE INDEX IND_TH01_ID ON TH01(ID) TABLESPACE TBS02;
Index created.
Elapsed: 00:00:33.03
SQL> execute dbms_stats.gather_table_stats('sywu','th01',cascade=>true);
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.17
SQL> @/oracle/getind
TABLE_NAME     INDEX_NAME    COLUMN_NAME    SIZE_GB    INDEX_TY   STATUS    LOGGING    DEGREE    NUM_ROWS    DISTINCT_KEYS
------------------------------ ------------------------------ ------------------------------ ---------- -------- -------- --------- ---------- -------- ---------- ------------- ---
TH01                    IND_TH01_ID          ID                    .091796875       NORMAL VALID             YES               1            DISABLED        5000000   5000000
显然对于高基数的列创建B-TREE索引是明智之选,对表进行分析后再次查询:
SQL>select id,name,gender,homeaddr from th01 where id=998698;
Elapsed: 00:00:00.00
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01 | 1 | 38 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_TH01_ID | 1 | | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=998698)
Statistics
----------------------------------------------------------
5 consistent gets
0 physical reads
基于成本的考虑,CBO优化器选择了通过索引的方式读取数据,一致读取5个块,有效减少了额外的物理读;做个基于索引列的统计查询:
SQL> select count(id) from th01;
Elapsed: 00:00:00.15
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 3170 (1)| 00:00:39 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
| 2 | INDEX FAST FULL SCAN| IND_TH01_ID | 5000K| 28M| 3170 (1)| 00:00:39 |
-------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
11810 consistent gets
11794 physical reads
CBO 优化器选择了全索引扫描,依旧消耗额外的资源;但当统计列发生改变时:
SQL> select count(*) from th01;
Elapsed: 00:00:00.14
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16707 (1)| 00:03:21 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TH01 | 5000K| 16707 (1)| 00:03:21 |
Statistics
----------------------------------------------------------
61221 consistent gets
61208 physical reads
此时CBO 优化器选择了全表扫描,并消耗更多的资源;

2.唯一B-TREE 索引:
在为表创建(主键、唯一约束)时,ORACLE 会默认创建一个B-TREE索引,这样既保证了数据的唯一性也提高了数据的检索效率:
SQL> alter table th01 add constraints cs_th01_uq unique(idcard);
Table altered.
Elapsed: 00:00:56.11
TABLE_NAME              INDEX_NAME             COLUMN_NAME             SIZE_GB    INDEX_TY      STATUS     LOGGING        DEGREE    COMPRESS    NUM_ROWS    DISTINCT_KEYS
------------------------------ ------------------------------ ------------------------------ ---------- -------- -------- --------- ---------- -------- ---------- ------------- ---
TH01                            CS_TH01_UQ                          IDCARD                        .15625               NORMAL           VALID                      YES                          1                      DISABLED    4969898                   4969898
以IDCARD查询人员信息:
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |         | 1 | 35 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01         | 1 | 35 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN         | CS_TH01_UQ | 1 |         | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("IDCARD"='562456864646565545')
Statistics
----------------------------------------------------------
3 consistent gets
0 physical reads
做为默认创建的索引,它依旧能高效的工作,但ORACLE是不允许将其作为独立的索引删除的,只能通过删除约束的方式删除;对于主键,它的情况要复杂些,因为还要考虑外键的约束;基于这种方式创建的索引,当约束被删除时还要重新创建索引,显然在一张大表上花费的代价和时间是昂贵的; so,采用如下的方式合理的建立约束和索引:
SQL> alter table th01 add constraints CS_TH01_UQ unique(idcard)
2* using index tablespace tbs03 ;
Table altered.
Elapsed: 00:00:59.27
倘若有一天业务发生了改变,唯一约束已经不是必须的,但索引是必须的,那只需要删除约束保留索引:
SQL> alter table th01 drop constraints CS_TH01_UQ keep index;
Table altered.
Elapsed: 00:00:00.01
再次通过IDCARD 查询人员信息:
SQL> select id,name,idcard from th01 where idcard='56234256878945';
------------------------------------------------------------------------------------------
| Id | Operation         | Name         | Rows | Bytes | Cost (%CPU)| Time         |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |         | 1 | 35 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01         | 1 | 35 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN         | CS_TH01_UQ | 1 |         | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("IDCARD"='56234256878945')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets

只创建唯一索引:
SQL> create unique index ind_th02 on th02(idcard) tablespace tbs03;
唯一索引与唯一约束相比,唯一索引只创建索引而不添加约束,它保证索引列数值唯一性,允许有空值;

3.复合索引:
可以在多个列上创建索引,其结果称为复合索引或组合索引:
SQL> create index ind_th01_union on th01(id,name,idcard) tablespace tbs03;
当查询的WHERE子句引用了索引的所有列或者只是前导列,CBO会使用复合索引
SQL>select id,name,idcard from th01 where idcard='9876534655635666' and id=68956254 and name='张三';
-----------------------------------------------------------------------------------
| Id | Operation         | Name | Rows | Bytes | Cost (%CPU)| Time         |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |         |        1 | 35 |        3 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| IND_TH01_UNION |        1 | 35 |        3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID"=68956254 AND "NAME"='张三' AND
"IDCARD"='9876534655635666')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
2 physical reads
通过查询结果,对于之前创建的单列索引(IND_TH01_ID、CS_TH01_UQ),优化器已不再使用;对于复合索引( IND_TH01_UNION) 来说, id | id, name| id,name,idcard 三个组合都被认为是前导列,假如我只是在WHERE 子句中引用了第一个主导列ID,那么优化器依旧会选择复合索引(IND_TH01_UNION )忽略单列索引( IND_TH01_ID)
SQL> select * from th01 where id=698698;
----------------------------------------------------------------------------------------------
| Id | Operation         | Name         | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |         |         1 |         77 |         4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01         |         1 |         77 |         4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN         | IND_TH01_UNION |         1 |         |         3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=698698)
Statistics
----------------------------------------------------------
0 db block gets
5 consistent gets

假如where 子句中的条件不符合复合索引前导列的要求,那么优化器会忽略复合索引( IND_TH01_UNION)选择单列索引(CS_TH01_UQ):
SQL> select * from th01 where idcard='5623546566564665';
------------------------------------------------------------------------------------------
| Id | Operation         | Name         | Rows | Bytes | Cost (%CPU)| Time         |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |         | 1 | 77 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01         | 1 | 77 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN         | CS_TH01_UQ | 1 |         | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("IDCARD"='5623546566564665')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
1 physical reads
对于此时的查询条件 where idcard='5623546566564665' 已经不再符合( id | id, name| id,name,idcard) 复合索引前导列的条件,优化器选择单列索引( CS_TH01_UQ);又假如,我的WHERE 子句条件符合复合索引前导列要求但不是全部满足:
SQL> select * from th01 where id=698698 and name='张三';
----------------------------------------------------------------------------------------------
| Id | Operation         | Name         | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |         |         1 |         77 |         4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TH01         |         1 |         77 |         4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN         | IND_TH01_UNION |         1 |         |         3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=698698 AND "NAME"='张三')
Statistics
----------------------------------------------------------
3 consistent gets
0 physical reads
通过分析(where id=698698 and name='张三' )符合复合索引前导列要求,优化器选择复合索引( IND_TH01_UNION) 忽略单列索引( IND_TH01_ID);
创建复合索引时,排序是个很大的问题,ORACLE 建议将最频繁访问的列放在索引中最靠前的位置,应避免使用低基数的列作为复合索引的前导列.



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-12138-1-1.html 上篇帖子: ORA-01033:ORACLE initialization or shutdown in process ORA-01219 数据库未... 下篇帖子: Oracle 空间管理

尚未签到

发表于 2014-1-12 00:44:59 | 显示全部楼层
有道理。。。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表