oracle优化(一)

时间:2020-12-24 23:47:29

非原创

1. 选用合适的ORACLE优化器

ORACLE的优化器有3种: a. RULE(基于规则)b. COST(基于成本) c. CHOOSE(选择性)

选择缺省的优化器,可以通过对init.ora中OPTIMIZER_MODE参数的各种声明,如RULE, COST, CHOOSE, ALL_ROWS, FIRST_ROWS。

你当然也可以在sql句级或是会话级别对其进行覆盖。

为了使用基于成本的优化器(CBO,Cost-Based Optimizer),你必须经常运行analyze命令,以增加数据库中的对象统计信息(object statistics)的准确性。

如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关.

如果table已经被analyze过,优化器模式将自动成为CBO, 反之数据库将采用RULE。

在缺省情况,Oracle将采用CHOOSE优化器,为了避免那些不必要的全表扫描,你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器。

2. 访问table的方式

ORACLE采用两种访问表中记录的方式:

a. 全表扫描

全表扫描就是顺序地访问表中每条记录.ORACLE采用一次读入多个数据块的方式优化全表扫描。

b. 通过ROWID访问表

你可以采用基于ROWID的访问方式,提高访问表的效率,ROWID包含了表中记录的物理位置信息。

ORACLE采用索引实现了数据和存放数据的物理位置(ROWID)之间的联系。通常索引提供了快

速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高。

3. 选择最有效的表名顺序(只在基于规则优化器中有效)

ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理

当ORACLE处理多个表,会运用排序及合并的方式连接它们。首先,扫描第一个表(FROM子句中最后那个)并对记录进行排序,然后扫描

第二个表,最后将所有从第二个表中检索出的记录与第一个表中合适的记录进行合并。

所以在FROM子句包含多个表的情况下,必须选择记录条数最少的表作为基础表。

4. WHERE子句中的连接顺序

ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉

最大数量记录的条件必须写在WHERE子句的末尾。

低效:select ... from emp e where sal>50000 and job='manager' and 25<(select count(*) from emp where mgr=e.empno);

高效:select ... from emp e where 25<(select count(*) from emp where mgr=e.empno) and sal>50000 and job='manager';

5. SELECT子句中避免使用 ' * '

ORACLE在解析时会将 ' * '依次转换成所有的列名,这个工作是查询数据字典完成,很耗时。

6. 减少访问数据库的次数

当执行每条SQL语句时,ORACLE在内部执行了许多工作:解析SQL,估算索引利用率,绑定变量,读数据块等。由此可见,

减少访问数据库的次数,就能实际上减少ORACLE的工作量。

低效:SELECT EMP_NAME, SALARY, GRAND FROM EMP WHERE EMP_NO=342;

SELECT EMP_NAME, SALARY, GRAND FROM EMP WHERE EMP_NO=291;

高效:SELECT A.EMP_NAME, A.SALARY, A.GRADE, B.EMP_NAME, B.SALARY, B.GRADE

FROM EMP A, EMP B WHERE A.EMP_NO=342 AND B.EMP_NO=291;

7. 使用DECODE函数减少处理时间

使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。

低效:SELECT COUNT(*), SUM(SAL) FROM EMP WHERE DEPT_NO=0020 AND ENAME LIKE 'SMITH%';

SELECT COUNT(*), SUM(SAL) FROM EMP WHERE DEPT_NO=0030 AND ENAME LIKE 'SMITH%';

高效:SELECT COUNT(DECODE(DEPT_NO, 0020,'X', NULL)) D0020_COUNT,

COUNT(DECODE(DEPT_NO, 0030,'X', NULL)) D0030_COUNT,

SUM(DECODE(DEPT_NO, 0020,SAL,NULL)) D0020_SAL,

SUM(DECODE(DEPT_NO, 0030,  SAL,  NULL)) D0030_SAL

FROM EMP WHERE ENAME LIKE 'SMITH%';

类似的,DECODE函数也可以运用于GROUP BY和ORDER BY子句中。

8. 整合简单无关联的数据库访问。

原始:SELECT NAME FROM EMP WHERE EMP_NO=1234;

SELECT NAME FROM  DPT WHERE DPT_NO=10;

SELECT NAME FROM CAT WHERE CAT_TYPE=‘RD’;

整合:SELECT E.NAME, D.NAME, C.NAME

FROM CAT C, DPT D, EMP E, DUAL X

WHERE NVL('X', X.DUMMY) = NVL('X', E.ROWID(+))

AND NVL('X', X.DUMMY) = NVL('X', D.ROWID(+))

AND NVL('X', X.DUMMY) = NVL('X', C.ROWID(+))

AND E.EMP_NO(+) = 1234

AND D.DEPT_NO(+) = 10

AND C.CAT_TYPE(+) = 'RD'

9. 删除重复记录

最高效的删除重复记录的方法(因为使用了ROWID)

DELETE FROM EMP E

WHERE E.ROWID >

(SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);