Oracle索引分析与比较(2)

 

26.5  附表(索引什么时候不工作)

首先要声明两个知识点:

1RBO&CBO

Oracle有两种执行优化器,一种是RBO(Rule Based Optimizer)基于规则的优化器,这种优化器是基于sql语句写法选择执行路径的;另一种是CBOCost Based Optimizer)基于规则的优化器,这种优化器是Oracle根据统计分析信息来选择执行路径,如果表和索引没有进行分析,Oracle将会使用RBO代替CBO;如果表和索引很久未分析,CBO也有可能选择错误执行路径,不过CBOOracle发展的方向,自8i版本来已经逐渐取代RBO.

2AUTOTRACE

要看索引是否被使用我们要借助Oracle的一个叫做AUTOTRACE功能,它显示了sql语句的执行路径,我们能看到Oracle内部是怎么执行sql的,这是一个非常好的辅助工具,在sql调优里广泛被运用。我们来看一下怎么运用AUTOTRACE

由于AUTOTRACE自动为用户指定了Execution Plan,因此该用户使用AUTOTRACE前必须已经建立了PLAN_TABLE。如果没有的话,请运行utlxplan.sql脚本(它在$ORACLE_HOME/rdbms/admin目录中)。

AUTOTRACE可以通过运行plustrce.sql脚本(它在$ORACLE_HOME/sqlplus/admin目录中)来设置,用sys用户登陆然后运行plustrce.sql后会建立一个PLUSTRACE角色,然后给相关用户授予PLUSTRACE角色,然后这些用户就可以使用AUTOTRACE功能了。

AUTOTRACE的默认使用方法是set autotrace on,但是这方法不总是适合各种场合,特别当返回行数很多的时候。Set autotrace traceonly提供了只查看统计信息而不查询数据的功能。

    SQL> set autotrace on

SQL> select * from test;

         A

----------

         1

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (FULL) OF 'TEST'

Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

          0  consistent gets

          0  physical reads

          0  redo size

          0  bytes sent via SQL*Net to client

          0  bytes received via SQL*Net from client

          0  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

rows processed

 

SQL> set autotrace traceonly

SQL> select * from test.test;

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (FULL) OF 'TEST'

Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

          0  consistent gets

          0  physical reads

          0  redo size

          0  bytes sent via SQL*Net to client

          0  bytes received via SQL*Net from client

          0  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

rows processed

HintsOracle提供的一个辅助用法,按字面理解就是'提示'的意思,确实它起得作用也是提示优化器按它所提供的关键字来选择执行路径,特别适用于sql调整的时候。使用方法如下:

{DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */

具体可参考Oracle SQL Reference

有了前面这些知识点,接下来让我们来看一下什么时候索引是不起作用的。以下列出几种情况。

 

1)类型不匹配时。

SQL> create table test.testindex (a varchar(2),b number);

表已创建。

SQL> create index ind_cola on test.testindex(a);

索引已创建。

SQL> insert into test.testindex values('1',1);

已创建 1 行。

SQL> commit;

提交完成。

SQL> analyze table test.testindex compute statistics for all indexes;

表已分析。

SQL> set autotrace on;

SQL> select /*+RULE */* FROM test.testindex where a='1';(使用基于rule的优化器,数据类型匹配的情况下)

A           B

-- ----------

1           1

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TESTINDEX'

   2    1     INDEX (RANGE SCAN) OF 'IND_COLA' (NON-UNIQUE)(使用了索引ind_cola

――――――――――――――――――――――――――――――――――

SQL> select /*+RULE */* FROM test.testindex where a=1;(数据类型不匹配的情况)

A           B

-- ----------

1           1

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (FULL) OF 'TESTINDEX'(优化器选择了全表扫描)

 

2)条件列包含函数但没有创建函数索引。

SQL> select /*+ RULE */*  FROM test.testindex where upper(a)= 'A';(使用了函数upper()在列a上);

A           B

-- ----------

a           2

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (FULL) OF 'TESTINDEX'(优化器选择全表扫描)

----------------------------------------------------------

创建基于函数的索引

SQL> create index test.ind_fun on test.testindex(upper(a));

索引已创建。

SQL> insert into testindex values('a',2);

已创建1行。

SQL> commit;

提交完成。

SQL> select /*+ RULE*/*  FROM test.testindex where upper(a)='A';

A           B

-- ----------

a           2

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (FULL) OF 'TESTINDEX'

(RULE优化器下忽略了函数索引选择了全表扫描)

-----------------------------------------------------------

SQL> select *  FROM test.testindex where upper(a)

='A';

A           B

-- ----------

a           2

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=5)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TESTINDEX' (Cost=2 Card=

          1 Bytes=5)

   2    1     INDEX (RANGE SCAN) OF 'IND_FUN' (NON-UNIQUE) (Cost=1 Car

          d=1)(CBO优化器使用了ind_fun索引)

 

3)复合索引中的前导列没有被作为查询条件。

创建一个复合索引

SQL> create index ind_com on test.testindex(a,b);

索引已创建。

SQL> select /*+ RULE*/* from test.testindex where a='1';

A           B

-- ----------

1           2

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   INDEX (RANGE SCAN) OF 'IND_COM' (NON-UNIQUE)(条件列表包含前导列时使用索引ind_com)

SQL> select /*+ RULE*/* from test.testindex where b=1;

未选定行

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (FULL) OF 'TESTINDEX'(条件列表不包括前导列是选择全表扫描)

-----------------------------------------------------------

 

4CBO模式下选择的行数比例过大,优化器采取了全表扫描。

SQL> select * from test.testindex where a='1';

A           B

-- ----------

1           2

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=5)

   1    0   TABLE ACCESS (FULL) OF 'TESTINDEX' (Cost=1 Card=1 Bytes=5)

(表一共2行,选择比例为50%,所以优化器选择了全表扫描)

――――――――――――――――――――――――――――――――――

下面增加表行数

SQL> declare i number;

  2  begin

  3  for i in 1 .. 100 loop

  4  insert into test.testindex values (to_char(i),i);

  5  end loop;

  6  end;

  7  /

PL/SQL 过程已成功完成。

SQL> commit;

提交完成。

SQL> select count(*) from test.testindex;

  COUNT(*)

----------

102

SQL> select * from test.testindex where a='1';

A             B

---- ----------

1             1

1             2

Execution Plan

SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=5)

1    0   INDEX (RANGE SCAN) OF 'IND_COM' (NON-UNIQUE) (Cost=1 Card=1 Bytes=5)

(表一共102行,选择比例为2/102=2%,所以优化器选择了索引扫描)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值