通过实验来说明oracle的数据库索引
实验1:
create table b0806 as select * from dba_objects;
create index ind_b0806 on b0806(object_id);
set autotrace traceonly;
select object_id from b0806 ;
实验结果:进行了全表扫描而没有走索引:
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 82624 | 1048K| 338 (1)| 00:00:05 |
| 1 | TABLE ACCESS FULL| B0806A | 82624 | 1048K| 338 (1)| 00:00:05 |
----------------------------------------------------------------------------
实验2
create table b0806a as select * from dba_objects;
alter table b0806a modify object_id not null;
create index ind_b0806a on b0806a(object_id);
set autotrace traceonly;
select object_id from b0806a;
实验2结果,走了索引
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 82624 | 1048K| 54 (0)| 00:00:0
1 |
| 1 | INDEX FAST FULL SCAN| IND_B0806A | 82624 | 1048K| 54 (0)| 00:00:0
1 |
--------------------------------------------------------------------------------
总结:
实验1之所以没有走索引是因为object_id有可能为null,null值是不存在索引的B*Tree数中的,因此数据库知道如果走了索引,
索引,那么为NULL的行就娶不到了,结果是不对的;实验2之所以走了索引,是因为,查询的列定义为了not null,这意味着
索引中能获取到全部的数据结果。
实验3--------------------------------------------------
create table a0806z as select * from dba_objects;
create index ind_a0806z on a0806z(object_id,object_type);
alter table a0806z modify (object_id not null);
alter table a0806z modify (object_type not null);
select object_id from a0806z ;--走索引
select object_type from a0806z ;--走索引
select object_id,object_type from a0806z where DATA_OBJECT_ID=800;--全表扫描,因为索引中找不到DATA_OBJECT_ID
select object_id,object_type from a0806z where object_id=1000;--走索引
select object_id,object_type from a0806z where object_type='VIEW';--走索引
select object_id,object_type from a0806z where object_id=1000 and object_type='VIEW';--走索引
select object_id,object_type,object_name from a0806z where object_id=1000;--走索引,这里由于查询的列object_name不在
索引中,因此当数据库遍历获取查询结果时,会先到索引的B*Tree中找到object_id=1000的记录,我们都知道索引的叶子节点保存了索引
列的值的同时,也保存了索引所在行的rowid(该行数据的物理地址),每一行object_name值的获取都要进行回表操作,消耗的性能比较大
那么问题来了,上面这条语句为什么还走索引?因为object_id=1000的结果行数不多,在这种场景oracle通过计算,即使需要回表,也比全表
扫描性能好,因此选择走索引,但是下面这行语句就恰好相反object_type='VIEW'值多。
select object_id,object_type,object_name from a0806z where object_type='VIEW';--全表扫描
---------------------------------------------------------------------------------------------------------------------
唯一索引
create table testind1(id number);
create unique index ind_testind1 on testind1(id);
insert into testind1 values(1);
insert into testind1 values(1);--插入时报错,因为索引指定了唯一索引,所以早构建B*Tree的时候不能出现相同的索引
insert into testind1 values(null);
insert into testind1 values(null);--插入不报错,因为null值不存储在B*Tree树中,不存B*Tree那么 unique index就不作用在这类数据上
create table testind2(id number,name varchar2(20));
create unique index ind_testind2 on testind2(id,name);
insert into testind2(id) values(1);
insert into testind2(id) values(1);--不报错,因为定义的是组合索引,两个唯一才叫唯一
insert into testind2(id,name) values(1,'a');
insert into testind2(id,name) values(1,'b');
insert into testind2 values(1,null);
insert into testind2 values(null,null);--不报错,null不存索引中
create table testind3(id number,name varchar2(20),local varchar2(20));
create unique index ind_testind3 on testind3(id,name,local);
insert into testind3(id) values(1);
insert into testind3(id) values(1);
insert into testind3(id,name) values(1,null);
insert into testind3(id,name) values(1,'a');
insert into testind3(id,name,local) values(1,null,'SZ');
insert into testind3(id,name) values(1,'b');
insert into testind3(id,name,local) values(1,'b','');
-------------------------------------------------------------------
create index ind_a0806 on a0806(object_type,object_id);
select object_id,object_type from a0806 where object_id=1000;
create index ind_a0806 on a0806(object_id,object_type);
create index ind_a0806 on a0806(object_type,object_id);
SQL> select OBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where OBJECT_NAME=XXX and OBJECT_id=
----------------------
SQL> create table b0806U as select * from dba_objects;
Table created.
SQL>
SQL> select count(*) from b0806U;
COUNT(*)
----------
75312
Execution Plan
----------------------------------------------------------
Plan hash value: 1290734131
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 293 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| B0806 | 72930 | 293 (1)| 00:00:04 |
--------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
6 recursive calls
0 db block gets
1143 consistent gets
1345 physical reads
0 redo size
424 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
动态分析
------------------
Analyze table b0806U compute statistics;
SQL> Analyze table b0806U compute statistics;
Table analyzed.
SQL>
SQL>
SQL>
SQL> select count(*) from b0806U;
COUNT(*)
----------
75312
Execution Plan
----------------------------------------------------------
Plan hash value: 1290734131
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 293 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| B0806 | 75312 | 293 (1)| 00:00:04 |
--------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1075 consistent gets
0 physical reads
0 redo size
424 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
SQL> create table c0806 as select * from dba_objects;
Table created.
SQL> select count(*) from c0806 where object_type='VIEW';
COUNT(*)
----------
5175
Execution Plan
----------------------------------------------------------
Plan hash value: 1298262899
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 294 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 11 | | |
|* 2 | TABLE ACCESS FULL| C0806 | 5474 | 60214 | 294 (1)| 00:00:04 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='VIEW')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
7 recursive calls
0 db block gets
1138 consistent gets
1329 physical reads
0 redo size
423 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
收集统计信息
SQL> Analyze table c0806 compute statistics;
SQL> select count(*) from c0806 where object_type='VIEW';
COUNT(*)
----------
5175
Execution Plan
----------------------------------------------------------
Plan hash value: 1298262899
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 294 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| C0806 | 1674 | 13392 | 294 (1)| 00:00:04 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='VIEW')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1075 consistent gets
0 physical reads
0 redo size
423 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
1* select count(distinct object_type) from dba_objects
45
SQL> select count(*) from c0806;
COUNT(*)
----------
75313
SQL> select 75313/45 from dual;
75313/45
----------
1673.62222
收集直方图
begin
dbms_stats.gather_table_stats(ownname => 'SYS',
tabname=>'C0806',
estimate_percent => 100,
method_opt => 'for all columns size skewonly'
);
end;
/
SQL> select count(*) from c0806 where object_type='VIEW';
SQL> select count(*) from c0806 where object_type='VIEW';
COUNT(*)
----------
5175
Execution Plan
----------------------------------------------------------
Plan hash value: 1298262899
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 294 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| C0806 | 5175 | 46575 | 294 (1)| 00:00:04 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='VIEW')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1075 consistent gets
0 physical reads
0 redo size
423 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
总结:
1.一个列如果是索引列,null值不存索引树中
2.索引其实也是数据库的对象,占用数据库存储,你可以在脑力里想象出一颗B*Tree结构
3.索引树的叶子节点保存了索引列的值,及索引列对应的行rowid物理地址