2013-08-07 星期三 天气:晴
-------------------------------索引的性能分析-----------------------
场景:假设数据块的大小8000字节,查询返回的记录行数是整表记录的20%
1、表有100000行数据,返回20000行数据,假如每行80字节,1块=100行,全表有1000块,
查询到的对应的叶子行有20000个,扫索引扫20000块次,全表扫,扫1000块次。
2、表有100000行数据,返回20000行数据,假如每行800字节,1块=10行,全表有10000块,
查询到的对应的叶子行有20000个,扫索引扫20000块次,全表扫,扫10000块次。
3、表有100000行数据,返回20000行数据,假如每行1600字节,1块=5行,全表有20000块,
查询到的对应的叶子行有20000个,扫索引扫20000块次,全表扫,扫20000块次。
4、表有100000行数据,返回20000行数据,假如每行8000字节,1块=1行,全表有100000块,
查询到的对应的叶子行有20000个,扫索引扫20000块次,全表扫,扫100000块次。
归纳:
A 不一定使用索引查询效率就会提升,场景1个场景2反而会下降。
B 索引的使用和块、行的比例有关系,块中含有的行越多扫索引的效率就会越低,
块中含有的行越少,扫索引的效率就会越高。和行的密度的有关系。
案例:研究RBO优化法则和CBO性能分析的差别
1、创建一个案例表
SQL> create table tx as select 1 id,object_name from all_objects;
Table created.
SQL> update tx set id=99 where rownum=1;
1 row updated.
SQL> commit;
Commit complete.
2、用RBO优化器生成执行计划
SQL> set autotrace trace exp
SQL> select /*+ rule */ * from tx where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 40191160
----------------------------------
| Id | Operation | Name |
----------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | TABLE ACCESS FULL| TX | --全表扫描
----------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1)
Note
-----
- rule based optimizer used (consider using cbo)
SQL> create index ind_tx on tx(id);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'tx',cascade=>true);
PL/SQL procedure successfully completed.
SQL> select /*+ rule */ * from tx where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 2614573569
----------------------------------------------
| Id | Operation | Name |
----------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| TX |
|* 2 | INDEX RANGE SCAN | IND_TX | --RBO下只要有索引一定会强制走索引的。
----------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=1)
Note
-----
- rule based optimizer used (consider using cbo)
SQL> select /*+ rule */ * from tx where id=99;
Execution Plan
----------------------------------------------------------
Plan hash value: 2614573569
----------------------------------------------
| Id | Operation | Name |
----------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| TX |
|* 2 | INDEX RANGE SCAN | IND_TX |
----------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=99)
Note
-----
- rule based optimizer used (consider using cbo)
================================================
3、用CBO生成执行计划
SQL> select * from tx where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 40191160
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 40919 | 1118K| 47 (3)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TX | 40919 | 1118K| 47 (3)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=1)
SQL> select /*+ index(tx ind_tx) */ * from tx where id=1; --CBO下,强制走索引代价很大。
Execution Plan
----------------------------------------------------------
Plan hash value: 2614573569
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 40919 | 1118K| 273 (1)| 00:00:04 |
| 1 | TABLE ACCESS BY INDEX ROWID| TX | 40919 | 1118K| 273 (1)| 00:00:04 |
|* 2 | INDEX RANGE SCAN | IND_TX | 40919 | | 81 (2)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=1)
SQL> set linesize 1000
SQL> select * from tx where id=99;
Execution Plan
----------------------------------------------------------
Plan hash value: 2614573569
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 28 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TX | 1 | 28 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_TX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=99)
查询列值分布数量很高的值,会全表扫,反之,才可能会用索引。
影响索引使用效率的三个影响因素:
1、块中行的密度
2、查询语句中where条件中的索引列引用值在列值中的分布情况。
3、索引和表数据放在同一个磁盘上,会发生IO的争用。
---------------------------------------------------
案例:分析B树索引的性能
SQL> drop table t1;
drop table t1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> create table t1(id int primary key,name varchar2(10));
Table created.
SQL> begin
2 for i in 1..10000 loop
3 insert into t1 values(i,'T1');
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> create table t2(id int primary key,name varchar2(10));
Table created.
SQL> begin
2 for i in 1..1000000 loop
3 insert into t2 values(i,'T2');
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t2',cascade=>true);
PL/SQL procedure successfully completed.
SQL> set autotrace trace exp --显示执行计划
SQL> select * from t1 where id=100;
Execution Plan
----------------------------------------------------------
Plan hash value: 1846342996
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 6 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | SYS_C006531 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=100)
SQL> select * from t2 where id=100;
Execution Plan
----------------------------------------------------------
Plan hash value: 3288443420
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 7 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | SYS_C006532 | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=100)
T1表的索引数只有两层,但是T2表的平衡树有三层,T3表在读取索引的时候会多读取一个根块。
查询层数:
----------------------------------------------------------
select * from user_indexes; --首先查看对应表的索引名
analyze index 索引名 validate structure; --分析
select * from index_stats --查看索引的统计信息
如下:
SQL> analyze index ind_obj_id validate structure;
Index analyzed
SQL> select * from index_stats;
HEIGHT BLOCKS NAME PARTITION_NAME LF_ROWS LF_BLKS LF_ROWS_LEN LF_BLK_LEN BR_ROWS BR_BLKS BR_ROWS_LEN BR_BLK_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN DISTINCT_KEYS MOST_REPEATED_KEY BTREE_SPACE USED_SPACE PCT_USED ROWS_PER_KEY BLKS_GETS_PER_ACCESS PRE_ROWS PRE_ROWS_LEN OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
---------- ---------- ------------------------------ ------------------------------ ---------- ---------- ----------- ---------- ---------- ---------- ----------- ---------- ----------- --------------- ------------- ----------------- ----------- ---------- ---------- ------------ -------------------- ---------- ------------ -------------- ----------------
2 384 IND_OBJ_ID 115766 273 1843607 7996 272 1 3750 8028 52956 839277 38598 3 2190936 1847357 85 2.×××745738 3.99963728690606 0 0 1 8
两次查询的代价是一样的,有了B树索引之后,查询的损耗不会因为表数据量的增加而增加,
即使数据量相差很大,当在唯一性索引或者主键索引查询的时候,消耗的资源几乎是没有区别的,
这就是索引发挥的巨大作用。
如果没有索引:
SQL> select /*+ full(t1) */ * from t1 where id=100;
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 6 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=100)
SQL> select /*+ full(t2) */ * from t2 where id=100;
Execution Plan
----------------------------------------------------------
Plan hash value: 1513984157
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 444 (7)| 00:00:06 |
|* 1 | TABLE ACCESS FULL| T2 | 1 | 7 | 444 (7)| 00:00:06 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=100)
update操作中索引的影响
SQL> update t1 set id=10001 where id=100;
1 row updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 2799287261
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 4 | 1 (0)| 00:00:01 |
| 1 | UPDATE | T1 | | | | |
|* 2 | INDEX UNIQUE SCAN| SYS_C006531 | 1 | 4 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=100)
SQL> update /*+ full(t1) */ t1 set id=10001 where id=100;
0 rows updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 2927627013
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 4 | 6 (0)| 00:00:01 |
| 1 | UPDATE | T1 | | | | |
|* 2 | TABLE ACCESS FULL| T1 | 1 | 4 | 6 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=100)
SQL> rollback;
Rollback complete.
SQL> update t2 set id=1000001 where id=100;
1 row updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 3398718552
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 5 | 2 (0)| 00:00:01 |
| 1 | UPDATE | T2 | | | | |
|* 2 | INDEX UNIQUE SCAN| SYS_C006532 | 1 | 5 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=100)
SQL> update /*+ full(t2) */ t2 set id=1000001 where id=100;
0 rows updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 2722410703
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 5 | 444 (7)| 00:00:06 |
| 1 | UPDATE | T2 | | | | |
|* 2 | TABLE ACCESS FULL| T2 | 1 | 5 | 444 (7)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=100)
SQL> rollback;
Rollback complete.
delete操作:
SQL> delete from t2 where id=100;
1 row deleted.
Execution Plan
----------------------------------------------------------
Plan hash value: 1328729220
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 1 | 5 | 2 (0)| 00:00:01 |
| 1 | DELETE | T2 | | | | |
|* 2 | INDEX UNIQUE SCAN| SYS_C006532 | 1 | 5 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=100)
SQL> delete /*+ full(t2) */ from t2 where id=100;
0 rows deleted.
Execution Plan
----------------------------------------------------------
Plan hash value: 1451993194
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 1 | 5 | 444 (7)| 00:00:06 |
| 1 | DELETE | T2 | | | | |
|* 2 | TABLE ACCESS FULL| T2 | 1 | 5 | 444 (7)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=100)
SQL> rollback;
Rollback complete.
注意:一定要where中用到索引列才能走索引:
SQL> update t2 set name='T11' where name='T2'; --没有用到索引列是一定不会走索引的。
1000000 rows updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 2722410703
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1013K| 2970K| 447 (8)| 00:00:06 |
| 1 | UPDATE | T2 | | | | |
|* 2 | TABLE ACCESS FULL| T2 | 1013K| 2970K| 447 (8)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("NAME"='T2')
SQL> update /*+ index(t2 SYS_C006532) */ t2 set name='T11' where name='T2'; --强制走索引代价巨大
1000000 rows updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 1100077776
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1013K| 2970K| 3728 (2)| 00:00:45 |
| 1 | UPDATE | T2 | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| T2 | 1013K| 2970K| 3728 (2)| 00:00:45 |
| 3 | INDEX FULL SCAN | SYS_C006532 | 1013K| | 1907 (2)| 00:00:23 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("NAME"='T2')
插入数据的PLAN
SQL> insert into t1 values(10001,'T11');
1 row created.
Execution Plan
----------------------------------------------------------
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | 6 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------
A 在HWM以下找连续的空间将数据插入
B 没有找到,在HWM之上插入数据,后HWM上移。
-------------------------------------
块中的行的分布密度对使用索引的影响。
SQL> conn hr/hr
Connected.
SQL> create table t3(id int primary key,name1 varchar2(2000),name2 varchar2(2000)); --行密度大的表
Table created.
SQL> create table t4(id int primary key,name1 char(2000),name2 char(2000)); --行密度小的表
Table created.
块大小是8K,预留10%的空间,实际每个块能存7373个字节,T4表的块只能放一行数据。
SQL> begin
2 for i in 1..20000 loop
3 insert into t3 values(i,'T3','T31');
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> begin
2 for i in 1..20000 loop
3 insert into t4 values(i,'T4','T41');
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t3',estimate_percent=>100,cascade=>true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t4',estimate_percent=>100,cascade=>true);
PL/SQL procedure successfully completed.
SQL> select * from t3 where id>17000;
Execution Plan
----------------------------------------------------------
Plan hash value: 4161002650
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3000 | 33000 | 14 (8)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T3 | 3000 | 33000 | 14 (8)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID">17000)
SQL> select * from t4 where id>17000; --行密度小的越容易用索引
Execution Plan
----------------------------------------------------------
Plan hash value: 1161789439
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3000 | 11M| 3011 (1)| 00:00:37 |
| 1 | TABLE ACCESS BY INDEX ROWID| T4 | 3000 | 11M| 3011 (1)| 00:00:37 |
|* 2 | INDEX RANGE SCAN | SYS_C006534 | 3000 | | 7 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID">17000)
SQL> set autotrace trace exp stat
SQL> select /*+ index(t3 SYS_C006533) */ * from t3 where id>17000;
3000 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2289016736
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3000 | 33000 | 14 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T3 | 3000 | 33000 | 14 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SYS_C006533 | 3000 | | 7 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID">17000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
415 consistent gets --走索引一致性读还是有差别的
0 physical reads
0 redo size
55787 bytes sent via SQL*Net to client
2589 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3000 rows processed
SQL> select * from t3 where id>17000;
3000 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4161002650
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3000 | 33000 | 14 (8)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T3 | 3000 | 33000 | 14 (8)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID">17000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
253 consistent gets
0 physical reads
0 redo size
55787 bytes sent via SQL*Net to client
2589 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3000 rows processed
T3表块上行分布密度比较大,用索引的概率小。T4表块上行分布密度小,用索引的概率大。
注意:上面这个实验要找到临界值才能成功的,临界值就是返回就录行数的值,
在这个值上走索引和全表扫的性能是一样的。
------------------------------------------------------------------
案例:B树索引使用的场合——键值重复率低的字段适合创建B树索引
SQL> create table t5 as select object_id,object_name from all_objects;
Table created.
SQL> create table t6 as select mod(object_id,2) object_id,object_name from all_objects; --ID字段重复率很高
Table created.
SQL> create index t3_ind on t5(object_id);
Index created.
SQL> create index t6_ind on t6(object_id);
Index created.
SQL> select count(distinct object_id) from t5;
COUNT(DISTINCTOBJECT_ID)
------------------------
40929
SQL> select count(distinct object_id) from t6;
COUNT(DISTINCTOBJECT_ID)
------------------------
2
SQL> exec dbms_stats.gather_table_stats(user,'t5',estimate_percent=>100,cascade=>true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t6',estimate_percent=>100,cascade=>true);
PL/SQL procedure successfully completed.
SQL> select * from t5 where object_id=1;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3812361271
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T5 | 1 | 30 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T3_IND | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=1)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
339 bytes sent via SQL*Net to client
389 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL> select * from t6 where object_id=1;
20511 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1930642322
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20465 | 539K| 46 (3)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T6 | 20465 | 539K| 46 (3)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=1)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1556 consistent gets
0 physical reads
0 redo size
626252 bytes sent via SQL*Net to client
15437 bytes received via SQL*Net from client
1369 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
20511 rows processed
强制T6走索引的话
SQL> select /*+ index(t6 T6_IND) */ * from t6 where object_id=1;
20511 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1497073299
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20465 | 539K| 228 (1)| 00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID| T6 | 20465 | 539K| 228 (1)| 00:00:03 |
|* 2 | INDEX RANGE SCAN | T6_IND | 20465 | | 40 (3)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=1)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2954 consistent gets
0 physical reads
0 redo size
626252 bytes sent via SQL*Net to client
15437 bytes received via SQL*Net from client
1369 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
20511 rows processed
oracle先要扫索引的叶子行,找到符合条件的键值,根据键值中的rowid到表中找到对应的行。
如果满足的条件很多,oracle不停的访问索引再访问表,如此循环。
SQL> select object_id from t5 where object_id=1; --查询索引列,不需要用rowid再去访问表了,
因为查询索引已经满足了要求。
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 2377336880
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| T3_IND | 1 | 5 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"=1)
SQL> select object_id from t6 where object_id=1;
20511 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3707116216
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20465 | 61395 | 20 (5)| 00:00:01 |
|* 1 | INDEX FAST FULL SCAN| T6_IND | 20465 | 61395 | 20 (5)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=1)
结论:创建索引的时候,要选择那些键值重复率低的字段。否则是很难用上的。