ORACLE SQL性能优化系列 (十)

** 31. 强制 索引失效 **



如果两个或以上索引具有相同的等级 , 你可以强制命令 ORACLE 优化器使用其中的一个 ( 通过它 , 检索出的记录数量少 ) .

举例 :

SELECT ENAME

FROM EMP

WHERE EMPNO = 7935

AND DEPTNO + 0 = 10 ** /*DEPTNO ** ** 上的索引将失效 */ **

AND EMP_TYPE || ‘’ = ‘A’ ** /*EMP_TYPE ** ** 上的索引将失效 */ **

这是一种相当直接的提高查询效率的办法 . 但是你必须谨慎考虑这种策略 , 一般来说 , 只有在你希望单独优化几个 SQL 时才能采用它 .

这里有一个例子关于何时采用这种策略 ,

假设在 EMP 表的 EMP_TYPE 列上有一个非唯一性的索引而 EMP_CLASS 上没有索引 .

SELECT ENAME

FROM EMP

WHERE EMP_TYPE = ‘A’

AND EMP_CLASS = ‘X’;

优化器会注意到 EMP_TYPE 上的索引并使用它 . 这是目前唯一的选择 . 如果 , 一段时间以后 , 另一个非唯一性建立在 EMP_CLASS 上 , 优化器必须对两个索引进行选择 , 在通常情况下 , 优化器将使用两个索引并在他们的结果集合上执行排序及合并 . 然而 , 如果其中一个索引( EMP_TYPE )接近于唯一性而另一个索引( EMP_CLASS )上有几千个重复的值 . 排序及合并就会成为一种不必要的负担 . 在这种情况下 , 你希望使优化器屏蔽掉 EMP_CLASS 索引 .

用下面的方案就可以解决问题 .

SELECT ENAME

FROM EMP

WHERE EMP_TYPE = ‘A’

AND EMP_CLASS ** ||’’ ** = ‘X’;

** 32. ** ** 避免在索引列上使用计算. **

WHERE 子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.

举例 :

低效:

SELECT …

FROM DEPT

WHERE SAL * 12 > 25000;

高效 :

SELECT …

FROM DEPT

WHERE SAL > 25000/12;

** 译者按 : **

** 这是一个非常实用的规则,请务必牢记 **

** 33. ** ** 自动选择索引 **

如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性.

在这种情况下, ORACLE 将使用唯一性索引而完全忽略非唯一性索引.

举例 :

SELECT ENAME

FROM EMP

WHERE EMPNO = 2326

AND DEPTNO = 20 ;

这里,只有 EMPNO 上的索引是唯一性的,所以 EMPNO 索引将用来检索记录.

TABLE ACCESS BY ROWID ON EMP

INDEX UNIQUE SCAN ON EMP_NO_IDX

** 34. ** ** 避免在索引列上使用 NOT **

通常, 我们要避免在索引列上使用 NOT, NOT 会产生在和在索引列上使用函数相同的

影响 . 当 ORACLE” 遇到 ”NOT, 他就会停止使用索引转而执行全表扫描 .

举例 :

低效 : ( 这里 , 不使用索引 )

SELECT …

FROM DEPT

WHERE DEPT_CODE NOT = 0;

高效 : ( 这里 , 使用了索引 )

SELECT …

FROM DEPT

WHERE DEPT_CODE > 0;

** 需要注意的是 , ** ** 在某些时候 , ORACLE ** ** 优化器会自动将 NOT ** ** 转化成相对应的关系操作符 ** .

NOT > to <=

NOT >= to <

NOT < to >=

NOT <= to >

** 译者按 : **

** ** ** 在这个例子中 , ** ** 作者犯了一些错误 . ** ** 例子中的低效率 SQL ** ** 是不能被执行的 . **

** 我做了一些测试 : **


** SQL> select * from emp where NOT empno > 1; **

** no rows selected **

** Execution Plan **

** ---------------------------------------------------------- **

** 0 SELECT STATEMENT Optimizer=CHOOSE **

** 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' **

** 2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE) **


** SQL> select * from emp where empno <= 1; **

** no rows selected **

** Execution Plan **

** ---------------------------------------------------------- **

** 0 SELECT STATEMENT Optimizer=CHOOSE **

** 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' **

** 2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE) **

** ** ** 两者的效率完全一样,也许这符合作者关于 ” ** ** 在某些时候 , ORACLE ** ** 优化器会自动将 NOT ** ** 转化成相对应的关系操作符 ” ** ** 的观点. **

** 35. ** ** 用 >= ** ** 替代 > **


如果 DEPTNO 上有一个索引 ,

高效 :

SELECT *

FROM EMP

WHERE DEPTNO >=4

低效 :

SELECT *

FROM EMP

WHERE DEPTNO >3

两者的区别在于 , 前者 DBMS 将直接跳到第一个 DEPT 等于 4 的记录而后者将首先定位到 DEPTNO=3 的记录并且向前扫描到第一个 DEPT 大于 3 的记录 .

Published At
Categories with 数据库类
Tagged with
comments powered by Disqus