1.
选
用适合的
ORACLE
优
化器
ORACLE
的
优
化器共有
3
种
A 、 RULE ( 基于 规则 ) b 、 COST ( 基于成本 ) c 、 CHOOSE ( 选择 性 )
设 置缺省的 优 化器,可以通 过对 init.ora 文件中 OPTIMIZER_MODE 参数的各 种 声明,如 RULE , COST , CHOOSE , ALL_ROWS , FIRST_ROWS 。 你当然也在 SQL 句 级 或是会 话 (session) 级对 其 进 行覆盖。
为 了使用基于成本的 优 化器 (CBO , Cost-Based Optimizer) , 你必 须经 常运行 analyze 命令,以增加数据 库 中的 对 象 统计 信息 (object statistics) 的准确性。
如果数据 库 的 优 化器模式 设 置 为选择 性 (CHOOSE) ,那 么实际 的 优 化器模式将和是否运行 过 analyze 命令有 关 。 如果 table 已 经 被 analyze 过 , 优 化器模式将自 动 成 为 CBO , 反之,数据 库 将采用 RULE 形式的 优 化器。
在缺省情况下, ORACLE 采用 CHOOSE 优 化器, 为 了避免那些不必要的全表 扫 描 (full table scan) , 你必 须 尽量避免使用 CHOOSE 优 化器,而直接采用基于 规则 或者基于成本的 优 化器。
2.
访问
Table
的方式
ORACLE
采用两
种访问
表中
记录
的方式:
A 、 全表 扫 描
全表 扫 描就是 顺 序地 访问 表中 每 条 记录 。 ORACLE 采用一次 读 入多个数据 块 (database block) 的方式 优 化全表 扫 描。
B 、 通 过 ROWID 访问 表
你可以采用基于 ROWID 的 访问 方式情况,提高 访问 表的效率, ROWID 包含了表中 记录 的物理位置信息。 ORACLE 采用索引 (INDEX) 实现 了数据和存放数据的物理位置 (ROWID) 之 间 的 联 系。通常索引提供了快速 访问 ROWID 的方法,因此那些基于索引列的 查询 就可以得到性 能上的提高。
3.
共享
SQL
语
句
为
了不重
复
解析相同的
SQL
语
句,在第一次解析之后,
ORACLE
将
SQL
语
句存放在内存中。
这块
位于系
统
全局区域
SGA(system global area)
的共享池
(shared buffer pool)
中的内存可以被所有的数据
库
用
户
共享。
因此,当你
执
行一个
SQL
语
句
(
有
时
被称
为
一个游
标
)
时
,如果它和之前的
执
行
过
的
语
句完全相同,
ORACLE
就能很快
获
得已
经
被解析的
语
句以及最好的
执
行路径。
ORACLE
的
这
个功能大大地提高了
SQL
的
执
行性能并
节
省了内存的使用。
可惜的是 ORACLE 只 对简单 的表提供高速 缓 冲 (cache buffering) , 这 个功能并不适用于多表 连 接 查询 。
数据 库 管理 员 必 须 在 init.ora 中 为这 个区域 设 置合适的参数,当 这 个内存区域越大,就可以保留更多的 语 句,当然被共享的可能性也就越大了。
当你向 ORACLE 提交一个 SQL 语 句, ORACLE 会首先在 这块 内存中 查 找相同的 语 句。 这 里需要注明的是, ORACLE 对 两者采取的是一 种严 格匹配,要达成共享, SQL 语 句必 须 完全相同 ( 包括空格, 换 行等 ) 。
数据 库 管理 员 必 须 在 init.ora 中 为这 个区域 设 置合适的参数,当 这 个内存区域越大,就可以保留更多的 语 句,当然被共享的可能性也就越大了。
共享的 语 句必 须满 足三个条件:
A 、 字符 级 的比 较 : 当前被 执 行的 语 句和共享池中的 语 句必 须 完全相同。
B 、 两个 语 句所指的 对 象必 须 完全相同:
C 、 两个 SQL 语 句中必 须 使用相同的名字的 绑 定 变 量 (bind variables) 。
4.
选择
最有效率的表名
顺
序
(
只在基于
规则
的
优
化器中有效
)
ORACLE
的解析器按照从右到左的
顺
序
处
理
FROM
子句中的表名,因此
FROM
子句中写在最后的表
(
基
础
表
driving table)
将被最先
处
理。在
FROM
子句中包含多个表的情况下,你必
须选择记录
条数最少的表作
为
基
础
表。当
ORACLE
处
理多个表
时
,
会运用排序及合并的方式
连
接它
们
。首先,
扫
描第一个表
(FROM
子句中最后的那个表
)
并
对记录进
行派序,然后
扫
描第二个表
(FROM
子句中最后第二个表
)
,最后将所有从第二个表中
检
索出的
记录
与第一个表中合适
记录进
行合并。
如果有 3 个以上的表 连 接 查询 , 那就需要 选择 交叉表 (intersection table) 作 为 基 础 表, 交叉表是指那个被其他表所引用的表。
5.WHERE
子句中的
连
接
顺
序
ORACLE
采用自下而上的
顺
序解析
WHERE
子句,根据
这
个原理,表之
间
的
连
接必
须
写在其他
WHERE
条件之前,
那些可以
过滤
掉最大数量
记录
的条件必
须
写在
WHERE
子句的末尾。
6.SELECT
子句中避免使用
' * '
当你想在
SELECT
子句中列出所有的
COLUMN
时
,使用
动态
SQL
列引用
'*'
是一个方便的方法。不幸的是,
这
是一个非常低效的方法。
实际
上,
ORACLE
在解析的
过
程中,
会将
'*'
依次
转换
成所有的列名,
这
个工作是通
过查询
数据字典完成的,
这
意味着将耗
费
更多的
时间
。
7.
减少
访问
数据
库
的次数
当
执
行
每
条
SQL
语
句
时
,
ORACLE
在内部
执
行了
许
多工作:解析
SQL
语
句,估算索引的利用率,
绑
定
变
量,
读
数据
块
等等。由此可
见
,减少
访问
数据
库
的次数,就能
实际
上减少
ORACLE
的工作量。
8.
使用
DECODE
函数来减少
处
理
时间
使用
DECODE
函数可以避免重
复扫
描相同
记录
或重
复连
接相同的表。
9.
整合
简单
,无
关联
的数据
库访问
如果你有几个
简单
的数据
库查询语
句,你可以把它
们
整合到一个
查询
中
(
即使它
们
之
间
没有
关
系
)
10.
删
除重
复记录
11.
用
TRUNCATE
替代
DELETE
当
删
除表中的
记录时
,在通常情况下,
回
滚
段
(rollback segments )
用来存放可以被恢
复
的信息。
如果你没有
COMMIT
事
务
,
ORACLE
会将数据恢
复
到
删
除之前的状
态
(
准确地
说
是恢
复
到
执
行
删
除命令之前的状况
)
。
而当运用 TRUNCATE 时 , 回 滚 段不再存放任何可被恢 复 的信息。当命令运行后,数据不能被恢 复 。因此很少的 资 源被 调 用, 执 行 时间 也会很短。
12.
尽量多使用
COMMIT
只要有可能,在程序中尽量多使用
COMMIT
,
这样
程序的性能得到提高,需求也会因
为
COMMIT
所
释
放的
资
源而减少
COMMIT 所 释 放的 资 源:
A 、 回 滚 段上用于恢 复 数据的信息。
B 、被程序 语 句 获 得的 锁 。
C 、 redo log buffer 中的空 间 。
D 、 ORACLE 为 管理上述 3 种资 源中的内部花 费 。
13.
计
算
记录
条数
和一般的
观
点相反,
count(*)
比
count(1)
稍快,当然如果可以通
过
索引
检
索,
对
索引列的
计
数仍旧是最快的。例如
COUNT(EMPNO)
14.
用
Where
子句替
换
HAVING
子句
避免使用
HAVING
子句,
HAVING
只会在
检
索出所有
记录
之后才
对结
果集
进
行
过滤
。
这
个
处
理需要排序,
总计
等操作。如果能通
过
WHERE
子句限制
记录
的数目,那就能减少
这
方面的
开销
。
15.
减少
对
表的
查询
在含有子
查询
的
SQL
语
句中,要特
别
注意减少
对
表的
查询
。
16.
通
过
内部函数提高
SQL
效率。
17.
使用表的
别
名
(Alias)
当在
SQL
语
句中
连
接多个表
时
,
请
使用表的
别
名并把
别
名前
缀
于
每
个
Column
上。
这样
一来,就可以减少解析的
时间
并减少那些由
Column
歧
义
引起的
语
法
错误
。
18.
用
EXISTS
替代
IN
在
许
多基于基
础
表的
查询
中,
为
了
满
足一个条件,往往需要
对
另一个表
进
行
联
接。在
这种
情况下,使用
EXISTS(
或
NOT EXISTS)
通常将提高
查询
的效率。
19.
用
NOT EXISTS
替代
NOT IN
在子
查询
中,
NOT IN
子句将
执
行一个内部的排序和合并。
无
论
在哪
种
情况下,
NOT IN
都是最低效的
(
因
为
它
对
子
查询
中的表
执
行了一个全表遍
历
)
。
为
了避免使用
NOT IN
,我
们
可以把它改写成外
连
接
(Outer Joins)
或
NOT EXISTS
。
20.
用表
连
接替
换
EXISTS
通常来
说
,
采用表
连
接的方式比
EXISTS
更有效率
21.
用
EXISTS
替
换
DISTINCT
当提交一个包含一
对
多表信息
(
比如部
门
表和雇
员
表
)
的
查询时
,避免在
SELECT
子句中使用
DISTINCT
。
一般可以考
虑
用
EXIST
替
换