Oracle 语句优化分析说明第1/2页

1. oracle 的解析器按照从右到左的顺序处理 from 子句中的表名,因此 from 子句中写在最后的表(基础表 driving table)将被最先处理。在 from 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。

例如:

表 tab1 16,384 条记录

表 tab2 1 条记录

选择 tab2作为基础表 (最好的方法)

select count(*) from tab1,tab2 执行时间 0.96秒

选择 tab2作为基础表 (不佳的方法)

select count(*) from tab2,tab1 执行时间 26.09秒

2. oracle 采用自下而上的顺序解析 where 子句,根据这个原理,表之间的连接必须写在其他 where 条件之前, 那些可以过滤掉最大数量记录的条件必须写在 where 子句的末尾。

例如:

(低效,执行时间 156.3秒)

select …

from emp e

where sal > 50000

and job = ‘manager’

and 25 < (select count(*) from emp

where mgr=e.empno);

(高效,执行时间 10.6秒)

select …

from emp e

where 25 < (select count(*) from emp

where mgr=e.empno)

and sal > 50000

and job = ‘manager’;

3. select子句中避免使用’*’

当你想在 select子句中列出所有的 column时,使用动态 sql列引用 ‘*’ 是一个方便的方法。不幸的是,这是一个非常低效的方法。 实际上,oracle 在解析的过程中,会将‘*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。

4. 使用decode 函数来减少处理时间, 使用 decode 函数可以避免重复扫描相同记录或重复连接相同的表。

5. 删除重复记录

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

delete from emp e

where e.rowid > (select min(x.rowid)

from emp x

where x.emp_no = e.emp_no);

6. 计算记录条数

和一般的观点相反,count(*) 比 count(1)稍快,当然如果可以通过索引检索,对索

引列的计数仍旧是最快的。 例如 count(empno)

7. 用where子句替换having子句

避免使用 having子句,having 只会在检索出所有记录之后才对结果集进行过滤。

这个处理需要排序,总计等操作。 如果能通过 where 子句限制记录的数目,那就能减少这方面的开销。

例如:

低效

select region,avg(log_size)

from location

group by region

having region region != ‘sydney’

and region != ‘perth’

高效

select region,avg(log_size)

from location

where region region != ‘sydney’

and region != ‘perth’

group by region

having 中的条件一般用于对一些集合函数的比较,如 count() 等等。除此而外,一般的条件应该写在 where 子句中。

8. 减少对表的查询

在含有子查询的 sql语句中,要特别注意减少对表的查询。

例如:

低效

select tab_name

from tables

where tab_name = ( select tab_name

from tab_columns

where version = 604)

and db_ver= ( select db_ver

from tab_columns

where version = 604)

高效

select tab_name

from tables

where (tab_name,db_ver)

= ( select tab_name,db_ver)

from tab_columns

where version = 604)

9. 使用表的别名alias

当在 sql语句中连接多个表时, 请使用表的别名并把别名前缀于每个 column上。这

样一来,就可以减少解析的时间并减少那些由 column歧义引起的语法错误。

(column歧义指的是由于 sql中不同的表具有相同的 column名,当 sql语句中出现这个 column时,sql解析器无法判断这个 column的归属)

10. 用exists替代in

在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。在这

种情况下, 使用 exists(或 not exists)通常将提高查询的效率。

低效:

select *

from emp (基础表)

where empno > 0

and deptno in (select deptno

from dept

where loc = ‘melb’)

高效:

select *

from emp (基础表)

where empno > 0

and exists (select ‘x’

from dept

where dept.deptno = emp.deptno

and loc = ‘melb’)

11. 用not exists替代 not in

在子查询中, not in子句将执行一个内部的排序和合并。 无论在哪种情况下, not in都是最低效的 (因为它对子查询中的表执行了一个全表遍历)。 为了避免使用 not in ,我们可以把它改写成外连接(outer joins)或 not exists.

例如:

select …

from emp

where dept_no not in (select dept_no

from dept

where dept_cat=’a’);

为了提高效率。改写为:

(方法一: 高效)

select ….

from emp a,dept b

where a.dept_no = b.dept(+)

and b.dept_no is null

and b.dept_cat(+) = ‘a’

(方法二: 最高效)

select ….

from emp e

where not exists (select ‘x’

from dept d

where d.dept_no = e.dept_no

and dept_cat = ‘a’);

12. 用表连接替换exists

通常来说 ,采用表连接的方式比 exists 更有效率

select ename

from emp e

where exists (select ‘x’

from dept

where dept_no = e.dept_no

and dept_cat = ‘a’);

(更高效)

select ename

from dept d,emp e

where e.dept_no = d.dept_no

and dept_cat = ‘a’ ;

13. 用exists替换distinct

当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在 select 子句

中使用 distinct. 一般可以考虑用 exist 替换

例如:

低效:

select distinct dept_no,dept_n

from dept d,emp e

where d.dept_no = e.dept_no

高效:

select dept_no,dept_name

from dept d

where exists ( select ‘x’

from emp e

where e.dept_no = d.dept_no);

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

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

举例:

低效:

select …

from dept

where sal * 12 > 25000;

高效:

select …

from dept

where sal > 25000/12;

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


1

(0)
上一篇 2022年3月22日
下一篇 2022年3月22日

相关推荐