ORACLE B-TREE(B树)索引
内容简介:
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
建议将最频繁访问的列放在索引中最靠前的位置,应避免使用低基数的列作为复合索引的前导列.
ORACLE B-TREE(B树)索引的更多相关文章
- Oracle索引梳理系列(二)- Oracle索引种类及B树索引
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
- 【转】 数据库系统——B+树索引
原文来自于:http://blog.csdn.net/cjfeii/article/details/10858721 1. B+树索引概述 在上一篇文章中,我们讨论了关于index的几个中重要的课题: ...
- Mysql存储引擎之TokuDB以及它的数据结构Fractal tree(分形树)
在目前的Mysql数据库中,使用最广泛的是innodb存储引擎.innodb确实是个很不错的存储引擎,就连高性能Mysql里都说了,如果不是有什么很特别的要求,innodb就是最好的选择.当然,这偏文 ...
- 浅谈B+树索引的分裂优化(转)
http://www.tamabc.com/article/85038.html 从MySQL Bug#67718浅谈B+树索引的分裂优化 原文链接:http://hedengcheng.com/ ...
- Oracle中NULL值与索引
NULL值是关系数据库系统布尔型(true,false,unknown)中比较特殊类型的一种值,通常称为UNKNOWN或空值,即是未知的,不确定的.由于NULL存在着无数的可能,因此NULL值也不等于 ...
- [转] Splay Tree(伸展树)
好久没写过了,比赛的时候就调了一个小时,差点悲剧,重新复习一下,觉得这个写的很不错.转自:here Splay Tree(伸展树) 二叉查找树(Binary Search Tree)能够支持多种动态集 ...
- 数据库系统——B+树索引
原文来自于:http://dblab.cs.toronto.edu/courses/443/2013/05.btree-index.html 1. B+树索引概述 在上一篇文章中,我们讨论了关于ind ...
- 深入研究B树索引(一)
摘要:本文对B树索引的结构.内部管理等方面做了一个全面的介绍.同时深入探讨了一些与B树索引有关的广为流传的说法,比如删除记录对索引的影响,定期重建索引能解决许多性能问题等. 1.B树索引的相关概念 索 ...
- MySQL的B树索引与索引优化
MySQL的MyISAM.InnoDB引擎默认均使用B+树索引(查询时都显示为"BTREE"),本文讨论两个问题: 为什么MySQL等主流数据库选择B+树的索引结构? 如何基于索引 ...
- Mysql B-Tree, B+Tree, B*树介绍
[摘要] 最近在看Mysql的存储引擎中索引的优化,神马是索引,支持啥索引.全是浮云,目前Mysql的MyISAM和InnoDB都支持B-Tree索引,InnoDB还支持B+Tree索引,Memory ...
随机推荐
- TransportClient操作详解
Elasticsearch JAVA操作有三种客户端: 1.TransportClient 2.JestClient 3.RestClient 还有种是2.3中有的NodeClient,在5.5.1中 ...
- 在Windows下搭建基于nginx的视频直播和点播系统
http://my.oschina.net/gaga/blog/478480 一.软件准备 由于nginx原生是为linux服务的,因此官方并没有编译好的windows版本可以下载,要在windows ...
- 05:Sysbench压测-innodb_deadlock_detect参数对性能的影响
目录 sysbench压测-innodb_deadlock_detect参数对性能的影响 一.OLTP测试前准备 二.进行OLTP测试 三.测试结果解读: 四.关于测试后的结论: 五.关于测试后的性能 ...
- eclipse使用SSH框架出现There is no Action mapped for namespace [/] and action name [] associated with context path错误
eclipse使用SSH框架出现There is no Action mapped for namespace [/] and action name [] associated with conte ...
- PHP5.3安装Zend Guard Loader代替Zend Optimizer
Zend Optimizer/3.3.3 解密加代码优化,提高PHP应用程序的执行速度,显著降低服务器的CPU负载. Zend Guard Loader/5.5.0/6.0 解密加代码优化,提 ...
- Python web框架 Tornado(三)自定义session组件
我们在学习Django框架的过程中,内部封装了session组件,以方便于我们使用进行验证.但是Tornado框架是没有session的,所以如果想使用session的话,就需要我们自己定制相对应的组 ...
- Android六大进程间通信方式总结之一:基本知识
因为不同进程都是享有独立资源的,所以全局变量这些都是无效的,必须有其他的进程间通信方式. 一.基本知识 1:怎样使用多进程 Android正常使用的多进程的办法只有一种,就是在Service或Acti ...
- 太白老师day6 1.代码块 2.is==id 3.小数据池
1.代码块: 一个模块一个函数一个类,一个文件都是代码块 在交互模式下, 每一行都是一个代码块 2. is == 内存地址 就是id门牌号 在内存中id是唯一,如果两个变量指向的id相同,那么他们在内 ...
- Elasticsearch 搜索引擎
简介: Elasticsearch 是一个实时的分布式搜索和分析引擎.它可以帮助你用前所未有的速度去处理大规模数据.它可以用于全文搜索,结构化搜索以及分析. 分布式实时文件存储,并将每一个字段都 ...
- Alternative PHP Cache ( APC )
简介: Alternative PHP Cache (APC) 是一个开放自由的PHP opcode 缓存.它的目标是提供一个自由.开放和健全的框架用于缓存和优化 PHP 的中间代码,加快 PHP 执 ...