oracle SQL性能优化

系统 1599 0
我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习、摘录、并汇总部分资料与大家分享!
1       选择 最有效率的表名 ( 只在基于 规则 化器中有效 )
ORACLE 的解析器按照从右到左的 FROM 子句中的表名, FROM 子句中写在最后的表 ( driving table) 将被最先 理,在 FROM 子句中包含多个表的情况下 , 你必 须选择记录 条数最少的表作 表。如果有 3 个以上的表 查询 , 那就需要 选择 交叉表 (intersection table) , 交叉表是指那个被其他表所引用的表 .
2       WHERE 子句中的 序.:
ORACLE 采用自下而上的 序解析 WHERE 子句 , 根据 个原理 , 表之 接必 写在其他 WHERE 条件之前 , 那些可以 过滤 掉最大数量 记录 的条件必 写在 WHERE 子句的末尾 .
3       SELECT 子句中避免使用 ‘ * ‘
ORACLE 在解析的 程中 , 会将 '*' 依次 转换 成所有的列名 , 个工作是通 过查询 数据字典完成的 , 意味着将耗 更多的 时间
4       减少 访问 数据 的次数:
ORACLE 在内部 行了 多工作 : 解析 SQL , 估算索引的利用率 , , 数据 等;
5       SQL*Plus , SQL*Forms Pro*C 中重新 ARRAYSIZE 参数 , 可以增加 次数据 库访问 索数据量 , 议值为 200
6       使用 DECODE 函数来减少 时间
使用 DECODE 函数可以避免重 复扫 描相同 记录 或重 复连 接相同的表 .
7       整合 简单 , 关联 的数据 库访问
如果你有几个 简单 的数据 库查询语 , 你可以把它 整合到一个 查询 ( 即使它 没有 )
8       除重 复记录
最高效的 除重 复记录 方法 ( 使用了 ROWID) 例子:
DELETE  FROM  EMP E  WHERE  E.ROWID > (SELECT MIN(X.ROWID)
FROM  EMP X  WHERE  X.EMP_NO = E.EMP_NO);
9       TRUNCATE 替代 DELETE
除表中的 记录时 , 在通常情况下 , (rollback segments ) 用来存放可以被恢 的信息 . 如果你没有 COMMIT ,ORACLE 会将数据恢 除之前的状 ( 准确地 是恢 除命令之前的状况 ) 而当运用 TRUNCATE , 段不再存 放任何可被恢 的信息 . 当命令运行后 , 数据不能被恢 . 因此很少的 源被 , 时间 也会很短 . ( 者按 : TRUNCATE 只在 除全表适用 ,TRUNCATE DDL 不是 DML)
10   尽量多使用 COMMIT
只要有可能 , 在程序中尽量多使用 COMMIT, 这样 程序的性能得到提高 , 需求也会因 COMMIT 放的 源而减少 :
COMMIT
放的 :
a.
段上用于恢 数据的信息 .
b.
被程序 得的
c. redo log buffer
中的空
d. ORACLE
管理上述 3 种资 源中的内部花
11   Where 子句替 HAVING 子句:
避免使用 HAVING 子句 , HAVING 只会在 索出所有 记录 之后才 对结 果集 过滤 . 理需要排序 , 总计 等操作 . 如果能通 WHERE 子句限制 记录 的数目 , 那就能减少 方面的 开销 . ( oracle ) on where having 三个都可以加条件的子句中, on 是最先 行, where 次之, having 最后,因 on 是先把不符合条件的 记录过滤 后才 统计 ,它就可以减少中 运算要 理的数据,按理 说应该 速度是最快的, where 应该 having 快点的,因 过滤 数据后才 sum ,在两个表 才用 on 的,所以在一个表的 候,就剩下 where having 了。在 这单 查询统计 的情况下,如果要 过滤 的条件没有 及到要 算字段,那它 果是一 的,只是 where 可以使用 rushmore ,而 having 就不能,在速度上后者要慢如果要 及到 算的字段,就表示在没 算之前, 个字段的 是不确定的,根据上篇写的工作流程, where 的作用 时间 是在 算之前就完成的,而 having 就是在 算后才起作用的,所以在 这种 情况下,两者的 果会不同。在多表 查询时 on where 更早起作用。系 首先根据各个表之 接条件,把多个表合成一个 临时 表后,再由 where 过滤 ,然后再 算, 算完后再由 having 过滤 。由此可 ,要想 过滤 条件起到正确的作用,首先要明白 个条件 应该 在什 么时 候起作用,然后再决定放在那里
12   减少 表的 查询
在含有子 查询 SQL 句中 , 要特 注意减少 表的 查询 . 例子:
     SELECT  TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER  FROM  TAB_COLUMNS   WHERE  VERSION = 604)
13   内部函数提高 SQL 效率 .
复杂 SQL 往往 牲了 行效率 . 掌握上面的运用函数解决 问题 的方法在 实际 工作中是非常有意
14   使用表的 (Alias)
当在 SQL 句中 接多个表 , 使用表的 名并把 名前 Column . 这样 一来 , 就可以减少解析的 时间 并减少那些由 Column 引起的 错误 .
15   EXISTS 替代 IN 、用 NOT EXISTS 替代 NOT IN
多基于基 表的 查询 , 足一个条件 , 往往需要 另一个表 . 这种 情况下 , 使用 EXISTS( NOT EXISTS) 通常将提高 查询 的效率 . 在子 查询 ,NOT IN 子句将 行一个内部的排序和合并 . 在哪 情况下 ,NOT IN 都是最低效的 ( 查询 中的表 行了一个全表遍 ). 了避免使用 NOT IN , 可以把它改写成外 (Outer Joins) NOT EXISTS.
例子:
高效 SELECT * FROM  EMP ( )   WHERE  EMPNO > 0   AND   EXISTS ( SELECT ‘X'   FROM DEPT   WHERE  DEPT.DEPTNO = EMP.DEPTNO   AND  LOC = ‘MELB')
( 低效 ) SELECT  * FROM  EMP ( )   WHERE  EMPNO > 0   AND  DEPTNO IN (SELECT DEPTNO   FROM  DEPT   WHERE  LOC = ‘MELB' )
16   识别 ' 低效 ' SQL 句:
然目前各 种关 SQL 化的 形化工具 出不 , 但是写出自己的 SQL 工具来解决 问题 是一个最好的方法:
SELECT  EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND ((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2 ) Hit_radio,
ROUND (DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM  V$SQLAREA
WHERE  EXECUTIONS>0
AND  BUFFER_GETS > 0
AND  (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY   4 DESC ;
17   用索引提高效率:
索引是表的一个概念部分 , 用来提高 索数据的效率, ORACLE 使用了一个 复杂 的自平衡 B-tree . 通常 , 索引 查询 数据比全表 描要快 . ORACLE 找出 查询 Update 句的最佳路径 , ORACLE 化器将使用索引 . 联结 多个表 使用索引也可以提高效率 . 另一个使用索引的好 , 它提供了主 (primary key) 的唯一性 验证 . 。那些 LONG LONG RAW 数据 , 你可以索引几乎所有的列 . 通常 , 在大型表中使用索引特 有效 . 当然 , 你也会 发现 , 描小表 , 使用索引同 能提高效率 . 然使用索引能得到 查询 效率的提高 , 但是我 也必 注意到它的代价 . 索引需要空 来存 , 也需要定期 维护 , 当有 记录 在表中增减或索引列被修改 , 索引本身也会被修改 . 意味着 记录 INSERT , DELETE , UPDATE 此多付出 4 , 5 次的磁 I/O . 索引需要 外的存 , 那些不必要的索引反而会使 查询 应时间变 . 定期的重构索引是有必要的 .
ALTER   INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
18   EXISTS DISTINCT
当提交一个包含一 多表信息 ( 比如部 表和雇 ) 查询时 , 避免在 SELECT 子句中使用 DISTINCT. 一般可以考 EXIST , EXISTS 使 查询 迅速 , RDBMS 核心模 将在子 查询 的条件一旦 足后 , 立刻返回 . 例子:
       ( 低效 ):
SELECT   DISTINCT  DEPT_NO,DEPT_NAME   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 ) ;
19   sql 句用大写的 ;因 oracle 是先解析 sql 句,把小写的字母 转换 成大写的再
20   java 中尽量 少用 接符 接字符串
21   避免在索引列上使用 NOT 通常 , 
要避免在索引列上使用 NOT, NOT 生在和在索引列上使用函数相同的影响 . ORACLE” 遇到 ”NOT, 他就会停止使用索引 行全表 .
22   避免在索引列上使用 算.
WHERE 子句中,如果索引列是函数的一部分. 化器将不使用索引而使用全表 描.
:
低效:
SELECT … FROM  DEPT  WHERE SAL * 12 > 25000;
高效 :
SELECT … FROM DEPT WHERE SAL > 25000/12;
23   >= 替代 >
高效 :
SELECT * FROM  EMP  WHERE  DEPTNO >=4
低效 :
SELECT * FROM EMP WHERE DEPTNO >3
两者的区 在于 , 前者 DBMS 将直接跳到第一个 DEPT 等于 4 记录 而后者将首先定位到 DEPTNO=3 记录 并且向前 描到第一个 DEPT 大于 3 记录 .
24   UNION OR ( 适用于索引列 )
通常情况下 , UNION WHERE 子句中的 OR 将会起到 好的效果 . 索引列使用 OR 将造成全表 . 注意 , 以上 规则 针对 多个索引列有效 . 如果有 column 没有被索引 , 查询 效率可能会因 你没有 选择 OR 而降低 . 在下面的例子中 , LOC_ID REGION 上都建有索引 .
高效 :
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效 :
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你 持要用 OR, 那就需要返回 记录 最少的索引列写在最前面 .
25   IN 来替 OR  
是一条 简单 规则 ,但是 实际 行效果 还须检验 ,在 ORACLE8i 下,两者的 行路径似乎是相同的. 
低效 :
SELECT …. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT FROM LOCATION WHERE LOC_IN   IN (10,20,30);
26   避免在索引列上使用 IS NULL IS NOT NULL
避免在索引中使用任何可以 空的列, ORACLE 将无法使用 索引. 列索引,如果列包含空 ,索引中将不存在此 记录 . 合索引,如果 个列都 空,索引中同 不存在此 记录 .  如果至少有一个列不 空, 则记录 存在于索引中. : 如果唯一性索引建立在表的 A 列和 B 列上 , 并且表中存在一条 记录 A,B 值为 (123,null) , ORACLE 将不接受下一条具有相同 A,B 123,null )的 记录 ( 插入 ). 然而如果所有的索引列都 空, ORACLE 认为 整个 键值为 空而空不等于空 . 因此你可以插入 1000 条具有相同 键值 记录 , 当然它 都是空 ! 不存在于索引列中 , 所以 WHERE 子句中 索引列 行空 将使 ORACLE 停用 索引 .
低效 : ( 索引失效 )
SELECT FROM  DEPARTMENT   WHERE  DEPT_CODE IS NOT NULL ;
高效 : ( 索引有效 )
SELECT FROM  DEPARTMENT   WHERE  DEPT_CODE >= 0;
27   是使用索引的第一个列:
如果索引是建立在多个列上 , 只有在它的第一个列 (leading column) where 子句引用 , 化器才会 选择 使用 索引 . 也是一条 简单 而重要的 规则 ,当 引用索引的第二个列 , 化器使用了全表 描而忽略了索引
28   UNION-ALL UNION ( 如果有可能的 )
SQL 句需要 UNION 两个 查询结 果集合 , 两个 果集合会以 UNION-ALL 的方式被合并 , 然后在 出最 终结 果前 行排序 . 如果用 UNION ALL 替代 UNION, 这样 排序就不是必要了 . 效率就会因此得到提高 . 需要注意的是 UNION ALL 将重 复输 出两个 果集合中相同 记录 . 因此各位 是要从 业务 需求分析使用 UNION ALL 的可行性 . UNION 对结 果集合排序 , 个操作会使用到 SORT_AREA_SIZE 这块 内存 . 这块 内存的 化也是相当重要的 . 下面的 SQL 可以用来 查询 排序的消耗量
低效:
SELECT  ACCT_NUM, BALANCE_AMT
FROM  DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效 :
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
29   WHERE 替代 ORDER BY
ORDER BY 子句只在两 种严 格的条件下使用索引 .
ORDER BY
中所有的列必 包含在相同的索引中并保持在索引中的排列 .
ORDER BY
中所有的列必 义为 非空 .
WHERE
子句使用的索引和 ORDER BY 子句中所使用的索引不能并列 .
例如 :
DEPT 包含以下列 :
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效 : ( 索引不被使用 )
SELECT DEPT_CODE  FROM  DEPT   ORDER BY  DEPT_TYPE
高效 : ( 使用索引 )
SELECT DEPT_CODE   FROM  DEPT   WHERE  DEPT_TYPE > 0
30   避免改 索引列的 .:
当比 不同数据 型的数据 , ORACLE 动对 简单 转换 .
EMPNO 是一个数 值类 型的索引列 .
SELECT …   FROM EMP   WHERE   EMPNO = ‘123'
实际 , 经过 ORACLE 转换 , :
SELECT …   FROM EMP  WHERE  EMPNO = TO_NUMBER(‘123')
幸运的是 , 转换 没有 生在索引列上 , 索引的用途没有被改 .
, EMP_TYPE 是一个字符 型的索引列 .
SELECT …   FROM EMP   WHERE EMP_TYPE = 123
句被 ORACLE 转换为 :
SELECT …   FROM EMP   WHERETO_NUMBER(EMP_TYPE)=123
内部 生的 转换 , 个索引将不会被用到 ! 了避免 ORACLE 你的 SQL 式的 转换 , 最好把 转换 式表 出来 . 注意当字符和数 较时 , ORACLE 转换 值类 型到字符
31   需要当心的 WHERE 子句 :
某些 SELECT 句中的 WHERE 子句不使用索引 . 里有一些例子 .
在下面的例子里 , (1) ‘!=' 将不使用索引 . , 索引只能告 你什 存在于表中 , 而不能告 你什 不存在于表中 . (2) ‘||' 字符 接函数 . 就象其他函数那 , 停用了索引 . (3) ‘+' 是数学函数 . 就象其他数学函数那 , 停用了索引 . (4) 相同的索引列不能互相比 , 将会启用全表 .
32   a. 如果 索数据量超 30% 的表中 记录 . 使用索引将没有 著的效率提高 .
b.
在特定情况下 , 使用索引也 会比全表 描慢 , 是同一个数量 上的区 . 而通常情况下 , 使用索引比全表 描要 几倍乃至几千倍 !
33   避免使用耗 费资 源的操作 :
DISTINCT,UNION,MINUS,INTERSECT,ORDER BY SQL 句会启 SQL 引擎
行耗 费资 源的排序 (SORT) 功能 . DISTINCT 需要一次排序操作 , 而其他的至少需要 行两次排序 . 通常 , UNION, MINUS , INTERSECT SQL 句都可以用其他方式重写 . 如果你的数据 SORT_AREA_SIZE 配得好 , 使用 UNION , MINUS, INTERSECT 也是可以考 , 竟它 的可 性很
34   GROUP BY:
提高 GROUP BY 句的效率 , 可以通 将不需要的 记录 GROUP BY 之前 过滤 . 下面两个 查询 返回相同 果但第二个明 就快了 .
低效 :
SELECT JOB , AVG(SAL)
FROM EMP
GROUP JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效 :
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP JOB
 

oracle SQL性能优化


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论