Oracle索引管理

Oracle索引管理

本文简单介绍了什么是索引,以及如果建索引,重点介绍了什么情况下建立了索引而查询时却没有使用,及一些简单的优化。
   
1 .简单介绍
    索引是建立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据,
    Oracle存储索引的数据结构是B*树,由根节点,分支节点和叶子节点组成,上级索引块包含有下级索引块的索引数据,叶子节点包含索引数据和确定行实际位置的rowid

2.如何建索引

一般把索引放到索引表空间里,使数据与索引分开放,合理设定 pctfress ,注意:不能给索引指定 pctused ;估计索引的大小和合理地设置存储参数,默认为表空间大小,或 initial next 设置成一样大。
建立索引的语法
其中 t 为表名,表中有两个字段 (i,v),ti_ind 为索引名, ind 为表空间名
B*- 树索引: create index ti_ind on t(i) tablespace ind
复合索引: create index tiv_ind on t(i,v) tablespace ind
函数索引: create index ti_ind on tablname(upper(i)) tablespace ind
位图索引, create bitmap index ti_ind on t(i) tablespace ind
唯一索引: create union index ti_ind on t(i) tablespace ind
反向索引: create index ti_ind on t(i) reverse tablespace ind

3.建立一个简单的索引

1.先建一个表
SQL> conn y / 123
SQL> create table t(i char(10),v number) tablespace test;
SQL> insert into t values('1',10);
SQL> insert into t values('2',20);
SQL> commit;
SQL> select * from t;
I                   V
---------- ----------
1                  10
2                  20
2.建立索引
SQL> create tablespace ind datafile '/oracle/ind.dbf' size 10M ;
SQL> conn y / 123
SQL> create index ti_ind on t(i) tablespace ind ;
建立索引其实是很简单的

4.使用索引

建立索引目的是加快访问表中的数据,我们可以使用 trace 工具查看当 select 数据时是全盘扫描,还是根据索引直接定位到数据。
打开 trace 工具
sql>@$ORACLE_HOME/rdbms/admin/utlxplan.sql
sql>@$ORACLE_HOME/sqlplus/admin/plustrce.sql
SQL>grant PLUSTRACE to public
SQL>set autot traceonly;
现在开始 select
SQL> select * from t where i='1';
Execution Plan
----------------------------------------------------------
Plan hash value: 2865601831
-------------------------------------------------------------------------------
| Id  | Operation           | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |    25 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T   |  1 |   25 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN   | TI_IND |   1 |     |    1   (0)| 00:00:01 |
可见数据是通过索引找到的,如果数据量非常大的话,使用索引会大大减小查询时间;

5.特殊情况

上面的例子可以看到当为某个表建立索引后,再在这个表查数据就使用索引,从而可能节省查询时间,提高查询效率,但在 oracle 中并不是建立索引就应用,如果在查询时对索引字段别加选项可能就不再应用索引而是全盘扫描了,如隐式数据转换, <> =NULL ,索引段加函数。
1.    隐式数据转换
就是当查询数据时,系统默认转换数据类型,如在上例中 i 字段类型为 char ,查询数据时使用了
select * from t where i='1'; 如果写成 select * from t where i=1; 也可以查出同样的数据,这时系统就把数值型数据 1 自动转换成字符‘ 1 了,
当系统有隐式数据转换时是不使用索引的,如下
SQL> select * from t where i=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
 
--------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |    25 |     7   (0)| 00:00:01 |
|*  1 | TABLE ACCESS FULL| T    |     1 |    25 |     7   (0)| 00:00:01 |
可见这时查找数据是通过全盘扫描查到的。
2.查询时,索引字段含有<>
SQL> select * from t where i<>'3';
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
----------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     2 |    50 |     7   (0)| 00:00:01 |
|*  1 | TABLE ACCESS FULL| T    |     2 |    50 |     7   (0)| 00:00:01 |
3.查询时,索引字段含有=NULL
SQL> select * from t where i='';
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 1322348184
-----------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    25 |     0   (0)|          |
|*  1 | FILTER     |      |       |       |            |          |
|   2 | TABLE ACCESS FULL| T    |     2 |    50 |     7   (0)| 00:00:01 |
4.查询时,索引字段使用了函数
先更改一条数据
update t set i='A' where v=10;
SQL> select * from t;
I                   V
---------- ------------
A                  10
2                  20
查询
SQL> select * from t where i='A';
  ---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time    
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT   |     |     1 |    25 |     2   (0)| 00:00:01 |
|   1 | TABLE ACCESS BY INDEX ROWID| T   |  1 |   25 |     2   (0)| 00:00:01 |
|*  2 | INDEX RANGE SCAN    | TI_IND |   1 |     |     1   (0)| 00:00:01 |
----------------------------------------------------------------------
使字段带函数再查询
SQL> select * from t where i=upper('a');  
Execution Plan
------------------------------------------------------------
Plan hash value: 1601196873
-------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    25 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    25 |     7   (0)| 00:00:01 |
-----------------------------------------------------------------
可见当给索引安段加上函数后就不使用索引了

6.简单优化

上面我们可以看到当对索引安段加上一些选项时就不再使用索引了,为了在查询时一定使用索引,可对参数 optimizer_index_cost_adj 进行设置,它的取值范围是 1---10000 ,值越小就越使用索引,而值越大就越全盘扫描
查看当前参数据值
SQL> show parameter optimizer_index_cost_adj
NAME                                 TYPE        VALUE
-------------------- ----------- ------------------------------
optimizer_index_cost_adj             integer     100
为了多使用索引,可减小它的值
SQL> alter system set optimizer_index_cost_adj=10;
System altered.
然后用索引字段使用了函数的语名查询
SQL> select * from t where i=upper('a');
|   0 | SELECT STATEMENT     |        |     1 |    25 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T  |   1 |    25 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN   | TI_IND |     1 |       |     1   (0)| 00:00:01 |
可见它此时也使用索引查询了
进一步设置
为了进一步优化, oracle 建议对小表不要建索引,那什么为小表呢, oracle 一次 I/O 就可读写完整个表的表为小表,查看 oracle 10g 一次读写的数据量
SQL> show parameter db_file_multiblock_read_count
NAME                                 TYPE        VALUE
---------------------- ----------- ------------------------------
db_file_multiblock_read_count                integer     128
可见当表小于 128k 时就不要建索引了
删除索引
SQL>drop index indexname
 

你可能感兴趣的:(oracle,优化,索引,管理,休闲)