原文:http://bbs.landingbj.com/t-0-240353-1.html
1、选用适合的 ORACLE 优化器
2、访问 Table 的方式
3、共享SQL语句
共享的语句必须满足三个条件
1) 字符级的比较,当前被执行的语句和共享池中的语句必须完全相同。
2) 两个语句所指的对象必须完全相同。
3) 两个 SQL 语句中必须使用相同的名字的绑定变量(bind variables)。
4、选择最有效率的表名顺序(只在基于规则的优化器中有效)
ORACLE 的解析器按照从右到左的顺序处理 FROM 子句中的表名,因此 FROM 子句中写在最后的表(基础表 driving table)将被最先处理。在 FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。
5、WHERE 子句中的连接顺序
ORACLE 采用自下而上的顺序解析 WHERE 子句,根据这个原理,表之间的连接必须写在其他 WHERE 条件之前。
6、SELECT 子句中避免使用 ‘ * ’
当 你想在 SELECT 子句中列出所有的 COLUMN 时,使用动态 SQL 列引用‘*’是一个方便的方法。不幸的是,这是一个非常低效的方法。实际 上,ORACLE 在解析的过程中,会将‘*’依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间。
7、减少访问数据库的次数
当执行每条 SQL 语句时,ORACLE 在内部执行了许多工作:解析 SQL 语句,估算索引的利用率,绑定变量,读数据块等等。由此可见,减少访问数据库的次数,就能实际上减少ORACLE 的工作量。
在 SQL*Plus,SQL*Forms 和 Pro*C 中重新设置 ARRAYSIZE 参数,可以增加每次数据库访问的检索数据量,建议值为 200。
8、使用 DECODE 函数来减少处理时间
使用 DECODE 函数可以避免重复扫描相同记录或重复连接相同的表。
9、整合简单,无关联的数据库访问
10、删除重复记录
最高效的删除重复记录方法:
where e.rowid > (select min(x.rowid) from emp x where x.emp_no = e.emp_no);
11、用 TRUNCATE 替代 DELETE
当 删除表中的记录时,在通常情况下,回滚段(rollback segments)用来存放可以被恢复的信息。如果你没有 COMMIT 事 务,ORACLE 会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)而当运用 TRUNCATE 时,回滚段不再存放任何可被恢 复的信息。当命令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短。TRUNCATE 只在删除全表适 用,TRUNCATE 是 DDL 不是 DML。
12、尽量多使用 COMMIT
COMMIT 所释放的资源:
回滚段上用于恢复数据的信息
被程序语句获得的锁
redo log buffer 中的空间
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 替换。
EXISTS 使查询更为迅速,因为 RDBMS 核心模块将在子查询的条件一旦满足后,立刻返回结果。
22、识别‘低效执行’的 SQL 语句
虽然目前各种关于 SQL 优化的图形化工具层出不穷,但是写出自己的 SQL 工具来解决问题始终是一个最好的方法。
23、使用 TKPROF 工具来查询 SQL 性能状态
24、用 EXPLAIN PLAN 分析 SQL 语句
EXPLAIN PLAN 是 一个很好的分析 SQL 语句的工具,它甚��可以在不执行 SQL 的情况下分析语句。通过分析,我们就可以知道 ORACLE 是怎么样连接表,使用 什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称。你需要按照从里到外,从上到下的次序解读分析的结果。EXPLAIN PLAN 分析的结果 是用缩进的格式排列的,最内部的操作将被最先解读,如果两个操作处于同一层中,带有最小操作号的将被首先执行。NESTED LOOP 是少数不按照上述 规则处理的操作,正确的执行路径是检查对 NESTED LOOP 提供数据的操作,其中操作号最小的将被最先处理。
注:目前许多第三方的工具如 TOAD 和 ORACLE 本身提供的工具如 OMS 的 SQL Analyze都提供了极其方便的 EXPLAIN PLAN 工具。
25、用索引提高效率
索 引是表的一个概念部分,用来提高检索数据的效率。实际上,ORACLE 使用了一个复杂的自平衡 B-tree 结构。通常,通过索引查询数据比全表扫描 要快。当 ORACLE 找出执行查询和 Update 语句的最佳路径时,ORACLE 优化器将使用索引。同样在联结多个表时使用索引也可以提高效 率。另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证。
除了那些 LONG 或 LONG RAW 数据类型,你可以索引几乎所有的列。通常,在大型表中使用索引特别有效。当然,你也会发现,在扫描���表时,使用索引同样能提高效率。
虽 然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价。索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身 也会被修改。这意味着每条记录的 INSERT,DELETE,UPDATE 将为此多付出 4,5 次的磁盘 I/O。因为索引需要额外的存储空间和处 理,那些不必要的索引反而会使查询反应时间变慢。
定期的重构索引是有必要的。
26、索引的操作
ORACLE 对索引有两种访问模式:
1) 索引唯一扫描(INDEX UNIQUE SCAN)
2) 索引范围查询(INDEX RANGE SCAN)
A. 基于一个范围的检索
B. 基于非唯一性索引的检索
27、基础表的选择
基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问)。根据优化器的不同,SQL 语句中基础表的选择是不一样的。
如果你使用的是 CBO(COST BASED OPTIMIZER),优化器会检查 SQL 语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径。
如果你用 RBO(RULE BASED OPTIMIZER),并且所有的连接条件都有索引对应,在这种情况下,基础表就是 FROM 子句中列在最后的那个表
28、多个平等的索引
如果不同表中两个相同等级的索引将被引用,FROM 子句中表的顺序将决定哪个会被率先使用。FROM 子句中最后的表的索引将有最高的优先级。
如果相同表中两个想同等级的索引将被引用,WHERE 子句中最先被引用的索引将有最高的优先级。
29、等式比较和范围比较
当 WHERE 子句中有索引列,ORACLE 不能合并它们,ORACLE 将用范围比较
30、不明确的索引等级
当 ORACLE 无法判��索引的等级高低差别,优化器将只使用一个索引,它就是在 WHERE子句中被列在最前面的。
31、强制索引失效
如果两个或以上索引具有相同的等级,你可以强制命令 ORACLE 优化器使用其中的一个(通过它,检索出的记录数量少)。
32、避免在索引列上使用计算
WHERE 子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。这是一个非常实用的规则,请务必牢记。
33、自动选择索引
如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性索引。在这种情况下,ORACLE 将使用唯一性索引,而完全忽略非唯一性索引
34、避免在索引列上使用 NOT
通常,我们要避免在索引列上使用 NOT,NOT 会产生在和在索引列上使用函数相同的影响。当 ORACLE 遇到 NOT,会停止使用索引转���执行全表扫描。
35、用>=替代>
36、用 UNION 替换 OR(适用于索引列)
37、用 IN 来替换 OR
38、避免在索引列上使用 IS NULL 和 IS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE 将无法使用该索引。对于单列索引,如’果列包含空值,索引中将不存在此记录。对于复合索引,如果每个列都为空,索引中同样不存在此记录。如果至少有一个列不为空,则记录存在于索引中。
39、总是使用索引的第一个列
40、ORACLE 内部操作
41、用 UNION-ALL 替换 UNION(如果有可能的话)
当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果��合会以 UNION-ALL 的方式被合并,然后在输出最终结果前进行排序。如果用 UNION ALL 替代 UNION,这样排序就不是必要了,效率就会因此得到提高。
NION 将对结果集合排序,这个操作会使用到 SORT_AREA_SIZE 这块内存。对于这块内存的优化也是相当重要的。
42、使用提示(Hints)
对于表的访问,可以使用两种 Hints:FULL 和 ROWID。
43、用 WHERE 替代 ORDER BY
ORDER BY 子句只在两种严格的条件下使用索引。
1) ORDER BY 中所有的列必须包含在相同的索引中并保持在索引中的排列顺序;
2) ORDER BY 中所有的列必须定义为非空。
WHERE 子句使用的索引和 ORDER BY 子句中所使用的索引不能并列。
44、避免改变索引列的类型
为了避免 ORACLE 对你的 SQL 进行隐式的类型转换,最好把类型转换用显式表现出来。注意当字符和数值比较时,ORACLE 会优先转换数值类型到字符类型。
45、需要当心的 WHERE 子句
46、连接多个扫描
如果你对一个列和一组有限的值进行比较,优化器可能执行多次扫描并对结果进行合并连接
47、CBO 下使用更具选择性的索引
48、避免使用耗费资源的操作
有 DISTINCT,UNION,MINUS,INTERSECT,ORDER BY 的 SQL 语 句会启动 SQL引擎执行耗费资源的排序(SORT)功能。DISTINCT 需要一次排序操作,而其他的至少需要执行两次排序。例如,一 个 UNION 查询,其中每个查询都带有 GROUP BY 子句,GROUP BY 会触发嵌入排序(NESTED SORT); 这样,每个查询需 要执行一次排序,然后在执行 UNION 时,又一个唯一排序(SORT UNIQUE)操作被执行而且它只能在前面的嵌入排序结束后才能开始执行。嵌入 的排序的深度会大大影响查询的效率。通常,带有 UNION,MINUS,INTERSECT 的 SQL 语句都可以用其他方式重写。
49、优化 GROUP BY
50、使用日期当心
使用日期时,需要注意如果有超过 5 位小数加到日期上,这个日期会进到下一天!
51、使用显式的游标(CURSORs)
使用隐式的游标,将会执行两次操作:第一次检索记录,第二次检查 TOO MANY ROWS这个 exception;而显式游标不执行第二次操作。
52、优化 EXPORT 和 IMPORT
53、分离表和索引
总 是 将 你 的 表 和 索 引 建 立 在 不 同 的 表 空 间 内 (TABLESPACES) 。 决 不 要 将 不 属 于ORACLE 内部系统的对象存放到 SYSTEM 表空间里。同时,确保数据表空间和索引表空间置于不同的硬盘上。