Oralce的性能优化之解析索引的前世今生
总结: 在oracle中索引就像一本书的目录一样,它可以加快查询速度,提高查询效率。在oracle中对于索引的存储采用B树索引来实现,B数索引是树形结构,存储时也是带枝带叶的。索引分为根节点,分支节点和叶子节点。
一>索引的内部信息深究
-----创建表
SQL> create table index_test as select * from user_objects; Table created
---在表的字段上创建索引
SQL> create index inx_test on index_test(object_id); Index created
---分析表
SQL> analyze index inx_test validate structure; Index analyzed
---查看索引的内部信息
SQL> select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats; HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS ---------- ---------- ---------- ---------- ---------- ----------- 1 8 0 1 48 0 SQL> select count(*) from index_test; COUNT(*) ---------- 48
----随机抽取几条数据作为后续的DML操作基础
SQL> select * from(select object_id from index_test order by dbms_random.value()) where rownum<5; OBJECT_ID ---------- 52647 53095 52646 51151
----选择第一条记录,作为一个update操作
SQL> update index_test set object_id=11111 where object_id=52647; 1 row updated
----分析表
SQL> analyze index inx_test validate structure; Index analyzed
----查看索引节点内部信息
SQL> select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats; HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS ---------- ---------- ---------- ---------- ---------- ----------- 1 8 0 1 49 1 ------尝试一个Insert操作 SQL> insert into index_test select * from index_test; 48 rows inserted ---分析表 SQL> analyze index inx_test validate structure; Index analyzed ----查看索引节点内部信息 SQL> select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats; HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS ---------- ---------- ---------- ---------- ---------- ----------- 1 8 0 1 96 0
二>索引的访问模式实践
(1)索引唯一扫描
----创建表
SQL> create table a as select object_id,object_name,object_type from dba_objects; Table created
---查看表结构
SQL> desc a; Name Type Nullable Default Comments ----------- ------------- -------- ------- -------- OBJECT_ID NUMBER Y OBJECT_NAME VARCHAR2(128) Y OBJECT_TYPE VARCHAR2(19) Y
---分析表
SQL> analyze table a compute statistics; Table analyzed
----创建唯一索引在a表的obkect_id字段上
SQL> create unique index ind_a on a(object_id); Index created SQL> set autot traceonly exp; Cannot SET AUTOT
----执行查询语句并查看执行计划
SQL> select * from a where object_id=258; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------------------------------------------------------------------- ------------------- 258 DUAL TABLE SQL> EXPLAIN PLAN FOR select * from a where object_id=258; Explained SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2087649606 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 36 | 2 (0)| 00:00 | 1 | TABLE ACCESS BY INDEX ROWID| A | 1 | 36 | 2 (0)| 00:00 |* 2 | INDEX UNIQUE SCAN | IND_A | 1 | | 1 (0)| 00:00 -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=258) 14 rows selected
(2)快速索引全扫描
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 Connected as scott@ORCL SQL> EXPLAIN PLAN FOR select * from a; Explained SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2248738933 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 50858 | 1787K| 73 (3)| 00:00:01 | | 1 | TABLE ACCESS FULL| A | 50858 | 1787K| 73 (3)| 00:00:01 | -------------------------------------------------------------------------- 8 rows selected SQL> select count(*) from a where object_id is null; COUNT(*) ---------- 0 简单的修改一些列的属性,排除NULL的干扰,就会走快速索引全扫描. SQL> alter table a nodify(object_id not null); table altered SQL> EXPLAIN PLAN FOR select object_id from a; Explained SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 672397539 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 50858 | 198K| 26 (4)| 00:00:01 | | 1 | INDEX FAST FULL SCAN| IND_A | 50858 | 198K| 26 (4)| 00:00:01 | ------------------------------------------------------------------------------ 8 rows selected
(3)索引全扫描
SQL> EXPLAIN PLAN FOR select * from a order by object_id; Explained SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 3699785968 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 50858 | 1787K| 467 (1)| 00:00 | 1 | TABLE ACCESS BY INDEX ROWID| A | 50858 | 1787K| 467 (1)| 00:00 | 2 | INDEX FULL SCAN | IND_A | 50858 | | 108 (2)| 00:00 -------------------------------------------------------------------------------- 9 rows selected
(4)区间扫描
如果涉及索引列的区间值,可以使用区间扫描,比如我们常用的between条件就会走区间扫描
SQL> EXPLAIN PLAN FOR select * from a where object_id between 2000 and 2050; Explained SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 1070634250 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 46 | 1656 | 3 (0)| 00:00 | 1 | TABLE ACCESS BY INDEX ROWID| A | 46 | 1656 | 3 (0)| 00:00 |* 2 | INDEX RANGE SCAN | IND_A | 46 | | 2 (0)| 00:00 -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID">=2000 AND "OBJECT_ID"<=2050) 14 rows selected