oracle SQL性能优化

我们要做到不但会写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*FormsPro*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只在除全表适用,TRUNCATEDDL不是DML)
10 尽量多使用COMMIT
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因COMMIT放的源而减少:
COMMIT
放的:
a.
段上用于恢数据的信息.
b.
被程序得的
c. redo log buffer
中的空
d. ORACLE
管理上述3种资源中的内部花
11 Where子句替HAVING子句:
避免使用HAVING子句, HAVING 只会在索出所有记录之后才对结果集过滤. 理需要排序,总计等操作. 如果能通WHERE子句限制记录的数目,那就能减少方面的开销.(oracle)onwherehaving三个都可以加条件的子句中,on是最先行,where次之,having最后,因on是先把不符合条件的记录过滤后才统计,它就可以减少中运算要理的数据,按理说应该速度是最快的,where应该having快点的,因过滤数据后才sum,在两个表才用on的,所以在一个表的候,就剩下wherehaving了。在这单查询统计的情况下,如果要过滤的条件没有及到要算字段,那它果是一的,只是where可以使用rushmore,而having就不能,在速度上后者要慢如果要及到算的字段,就表示在没算之前,个字段的是不确定的,根据上篇写的工作流程,where的作用时间是在算之前就完成的,而having就是在算后才起作用的,所以在这种情况下,两者的果会不同。在多表查询时onwhere更早起作用。系首先根据各个表之接条件,把多个表合成一个临时表后,再由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)的唯一性验证.。那些LONGLONG RAW数据, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特有效. 当然,你也会发现, 描小表,使用索引同能提高效率. 然使用索引能得到查询效率的提高,但是我也必注意到它的代价. 索引需要空来存,也需要定期维护, 当有记录在表中增减或索引列被修改, 索引本身也会被修改. 意味着记录INSERT , DELETE , UPDATE此多付出4 , 5 次的磁I/O . 索引需要外的存,那些不必要的索引反而会使查询应时间变.定期的重构索引是有必要的.
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
18 EXISTSDISTINCT
当提交一个包含一多表信息(比如部表和雇)查询时,避免在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 UNIONOR (适用于索引列)
通常情况下, UNIONWHERE子句中的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
高效
SELECTFROM LOCATION WHERE LOC_IN  IN (10,20,30);
26 避免在索引列上使用IS NULLIS NOT NULL
避免在索引中使用任何可以空的列,ORACLE将无法使用索引.列索引,如果列包含空,索引中将不存在此记录. 合索引,如果个列都空,索引中同不存在此记录. 如果至少有一个列不空,则记录存在于索引中.: 如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B123,null)的记录(插入). 然而如果所有的索引列都空,ORACLE认为整个键值为空而空不等于空. 因此你可以插入1000 条具有相同键值记录,当然它都是空! 不存在于索引列中,所以WHERE子句中索引列行空将使ORACLE停用索引.
低效: (索引失效)
SELECTFROM  DEPARTMENT  WHERE  DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECTFROM  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 BYSQL句会启SQL引擎
行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要行两次排序. 通常, UNION, MINUS , INTERSECTSQL句都可以用其他方式重写. 如果你的数据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
 
posted @ 2008-01-30 17:34  hibernate3例子  阅读(167)  评论(0编辑  收藏  举报