Oracle数据库如何提高访问性能

来源:互联网 发布:淘宝的xbox one手柄 编辑:程序博客网 时间:2024/06/05 04:43

Oracle数据库如何提高访问性能

a)        避免在索引列上使用ISNULL和IS NOT NULL 操作

避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.
举例: 
如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000 条具有相同键值的记录,当然它们都是空! 因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.

b)        用UNION替换OR (适用于索引列) 
通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.

c)        分离表和索引 
总是将你的表和索引建立在不同的表空间内(TABLESPACES). 决不要将不属于ORACLE内部系统的对象存放到SYSTEM表空间里. 同时,确保数据表空间和索引表空间置于不同的硬盘上(通过指定表空间的方式可以实现这个要求).

d)        共享SQL语句

为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(systemglobal area)的共享池(sharedbuffer pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用. 
当你向ORACLE提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句. 
这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同(包括空格,换行等).

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

示例1.(低效,执行时间156.3秒) 
SELECT* FROM EMP E 
WHERE SAL > 50000 
AND JOB = ‘MANAGER' AND 25 < (SELECT COUNT(*) FROM EMP 
WHERE MGR=E.EMPNO); 
示例2(高效,执行时间10.6秒) 
SELECT … FROM EMP E 
WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO) 
AND SAL > 50000 
AND JOB = ‘MANAGER';

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

g)        使用DECODE函数来减少处理时间 
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. 
例如: 
SELECT COUNT(*),SUM(SAL) 
FROM EMP 
WHERE DEPT_NO = 0020 
AND ENAME LIKE ‘SMITH%';


SELECT COUNT(*),SUM(SAL) 
FROM EMP 
WHERE DEPT_NO = 0030 
AND ENAME LIKE ‘SMITH%'; 
你可以用DECODE函数高效地得到相同结果 
SELECT COUNT(DECODE(DEPT_NO,0020,'X',NULL)) D0020_COUNT, 
COUNT(DECODE(DEPT_NO,0030,'X',NULL)) D0030_COUNT, 
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL, 
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL 
FROM EMP WHERE ENAME LIKE ‘SMITH%'; 
类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.

h)        用TRUNCATE替代DELETE 
当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. 
(注意: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)

i)          尽量多使用COMMIT
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少: 
COMMIT所释放的资源: 
a. 回滚段上用于恢复数据的信息. 
b. 被程序语句获得的锁 
c. redo log buffer 中的空间 
d. ORACLE为管理上述3种资源中的内部花费 
(注意: 在使用COMMIT时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼)

j)          用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子句中)

k)        用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')

l)          用NOTEXISTS替代NOTIN 
在子查询中,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');

原创粉丝点击