索引的概念
索引是oracle的一个对象,是否使用索引由oracle决定,索引中存储了特定列的排序数据,实现对表的快速访问。
使用索引可以很快速查找到建立索引时列的值所在的行,而不必对表实现全表扫描,适当使用索引可以减少磁盘的I/O量。
索引的特点:
- 对于具有只读特性或较少插入、更新或删除操作的大表通常可以提高查询速度。
- 可以对表的一列或多列建立索引。
- 建立索引的数量没有限制。
- 索引需要磁盘储存,需要oracle自动维护。
- 索引对用户透明,是否使用索引是oracle决定的。
Oracle实现数据访问的方法
- 全表扫描
- 通过ROWID
- 使用索引
-
全表扫描
SQL> explain plan for select*from dual;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
已选择8行。
-
通过行ID(略)
-
使用索引
通过索引找到数据行的ROWID,然后通过ROWID直接到表中查找数据,这种方式成为索引查找或者索引扫描。
因为一个ROWID对应一个数据行,因此这种方式采用的也是单块读。
在索引中,除了存储每一个索引值,还会存储相应的ROWID,索引扫描分为两步:
- 扫描索引得到相应的ROWID。
- 通过找到ROWID从表中读取对应的数据。
通过执行计划判断索引的使用
SQL> explain plan for select * from scott.emp where empno=10;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2949544139
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------
2 - access("EMPNO"=10)
已选择14行。
索引扫描类型
根据索引类型、数据分布以及SQL等确定索引的扫描类型。
- 索引唯一扫描(INDEX UNIQUE SCAN)
- 索引范围扫描(INDEX RANGE SCAN)
- 索引全扫描(INDEX FULL SCAN)
- 索引快速扫描(INDEX FAST FULL SCAN)
-
索引唯一扫描
索引唯一扫描通过指定UNIQUE键、主键,oracle通常返回一个数据行,因此采用的索引唯一扫描。
SQL> explain plan for select * from emp where empno=10;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2949544139
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------
2 - access("EMPNO"=10)
已选择14行。
-
索引范围扫描
如果发生如下情况时候需要使用使用索引范围扫描:
在unique键上使用range操作符(> , < , <> , >= , <= , between)
在组合索引上,只使用部分列进行查询,导致查询出多行
对非唯一索引列上进行查询
使用索引范围扫描
SQL> explain plan for select * from emp where empno>10;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 169057108
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 532 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 532 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PK_EMP | 14 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------
2 - access("EMPNO">10)
已选择14行。
-
扫描全索引
当使用索引全扫描时,查询出的数据必须全部从索引中得到
SQL> explain plan for select * from emp;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 532 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMP | 14 | 532 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
已选择8行。
-
索引快速扫描
索引快速扫描,扫描索引快中的所有数据块,与全扫描相类似,但是索引快速扫描不进行数据排序,在这种方式下,可以使用多块读功能、也可以使用并行读功能,最大化吞吐量。
使用索引快速扫描
SQL> explain plan for select empno,ename from emp;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 140 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMP | 14 | 140 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
已选择8行。
限制索引使用的情况
很多情况及时创建了索引,也会导致索引不能使用。
-
使用不等于运算符
使用度等于运算符 < , > , != 在where中使用这些不等于条件,将会导致索引失败
SQL> explain plan for select * from emp where empno<>10;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 532 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 14 | 532 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 - filter("EMPNO"<>10)
已选择13行。
-
使用IS NULL 或者 IS NOT NULL
在where子句中使用IS NULL或者IS NOT NULL 同样会限制索引使用。
NULL判断影响索引使用(基于emp表SAL列创建B树索引)
SQL> select column_name from user_ind_columns where table_name='EMP';
COLUMN_NAME
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EMPNO
SQL> explain plan for select * from emp;
已解释。
SQL> select column_name from user_ind_columns where table_name='EMP';
COLUMN_NAME
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EMPNO
SQL> create index idx_sal_emp on emp(sal);
索引已创建。
SQL> select column_name from user_ind_columns where table_name='EMP';
COLUMN_NAME
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SAL
EMPNO
不走索引走全表扫描
SQL> explain plan for select empno,ename,deptno from emp;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 182 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMP | 14 | 182 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
已选择8行。
建立索引
oracle建立索引使用CREATE INDEX来建立
对EMP表建立索引
SQL> create index emp_ename_idx on emp(ename);
索引已创建。
使用USER_INDEXES数据字典查询索引信息
从数据字典 USER_INDEXES可以详细地查看当前用户所拥有的索引信息,
SQL> select index_name,index_type,table_name,tablespace_name from user_indexes;
INDEX_NAME INDEX_TYPE
------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------
TABLE_NAME TABLESPACE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
PK_EMP NORMAL
EMP USERS
IDX_SAL_EMP NORMAL
EMP USERS
EMP_ENAME_IDX NORMAL
EMP USERS
INDEX_NAME INDEX_TYPE
------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------
TABLE_NAME TABLESPACE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
PK_DEPT NORMAL
DEPT USERS
创建索引表空间
SQL> create tablespace index_tbs
2 datafile '/u01/app/oracle/oradata/tiqs/index_tbsl.dbf' size 100M autoextend on ;
表空间已创建。
创建多列索引
SQL> create index emp_name_sal_index on emp(ename,sal)
2 tablespace index_tbs;
索引已创建。
查看多列索引
SQL> select index_name,table_name,tablespace_name from user_indexes where index_name like '%EMP%';
INDEX_NAME TABLE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
TABLESPACE_NAME
------------------------------------------------------------------------------------------
PK_EMP EMP
USERS
IDX_SAL_EMP EMP
USERS
EMP_ENAME_IDX EMP
USERS
INDEX_NAME TABLE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
TABLESPACE_NAME
------------------------------------------------------------------------------------------
EMP_NAME_SAL_INDEX EMP
INDEX_TBS
查看索引
数据字典USER_IND_COLUMNS使得我们可以很方便查找一个索引所对应列的信息。
查询索引列相关的信息
SQL> select index_name,table_name,column_name from user_ind_columns;
INDEX_NAME TABLE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
COLUMN_NAME
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EMP_ENAME_IDX EMP
ENAME
EMP_NAME_SAL_INDEX EMP
SAL
EMP_NAME_SAL_INDEX EMP
ENAME
INDEX_NAME TABLE_NAME
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
COLUMN_NAME
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IDX_SAL_EMP EMP
SAL
PK_DEPT DEPT
DEPTNO
PK_EMP EMP
EMPNO
已选择6行。
重建索引
索引需要维护,不然如果建立了索引的表中有大量的删除和插入操作会使得索引很大,因为删除操作后,删除值所占用的索引空间不能够诶索引自动重新使用,而插入操作会不断使得索引变大
SQL> alter index emp_name_sal_index rebuild;
索引已更改。
SQL> alter index emp_name_sal_index rebuild tablespace tablespace_name;
索引已更改。
SQL> alter index emp_name_sal_index rebuild online;
索引已更改。
维护索引
维护索引就是修改索引的各种参数,在维护索引前首先需要指导当前索引的参数设置。
查询当前索引的参数设置
SQL> select index_name,pct_free,pct_increase,initial_extent,next_extent from user_indexes;
INDEX_NAME PCT_FREE PCT_INCREASE INITIAL_EXTENT NEXT_EXTENT
------------------------------------------------------------------------------------------ ---------- ------------ -------------- -----------
PK_EMP 10 65536 1048576
IDX_SAL_EMP 10 65536 1048576
EMP_ENAME_IDX 10 65536 1048576
EMP_NAME_SAL_INDEX 10 65536 1048576
PK_DEPT 10 65536 1048576
通过rubuild修改索引参数
手动增加索引的磁盘空间
SQL> alter index EMP_ENAME_IDX allocate extent;
索引已更改。
合并索引碎片
SQL> alter index emp_ename_idx coalesce;
索引已更改。
删除索引
SQL> drop index emp_name_sal_index;
索引已删除。
SQL> select index_name,pct_free,pct_increase,initial_extent,next_extent from user_indexes;
INDEX_NAME PCT_FREE PCT_INCREASE INITIAL_EXTENT NEXT_EXTENT
------------------------------------------------------------------------------------------ ---------- ------------ -------------- -----------
PK_EMP 10 65536 1048576
IDX_SAL_EMP 10 65536 1048576
EMP_ENAME_IDX 10 65536 1048576
PK_DEPT 10 65536 1048576