您的位置:首页 > 数据库 > Oracle

oracle性能优化总结

2016-04-06 18:37 387 查看

Oracle性能优化

一.数据库优化的方向

1.程序设计(这点最重要,如果程序本身设计有问题,再怎么进行下面的优化都是徒劳的。)

2.操作系统优化

3.硬件优化

4.数据库优化

5.SQL语句优化

二.硬件优化

这里涉及到的硬件主要有:硬盘,内存。

1.硬盘的读写速度:建议增加硬盘的数量,从而增加每秒的并发操作。

2.内存大小。

三.数据库优化

以上是Oracle 9i的体系结构,关于Oracle数据库的优化,很大程度上图有关。

1.根据数据库的使用方式得出合理的优化策略

(1)OLTP:连机事务处理。

需要实时处理大量请求,而每次处请求的数据量都是很小的。OLTP是传统的关系型数据库的主要应用,

主要是基本的、日常的事务处理,例如银行交易。

性能好坏的重要指标:响应时间与请求处理并发数。

(2)OLAP:联机分析处理。

可以简单地理解为在海量数据中得出统计/综合信息,是数据仓库的主要应用。做OLAP应用的数据库,数

据量通常量非常大。和OLTP不同,OLAP应用的并发处理量是很低的,所以基本不用考虑并发问题。而在

处理数据量方面,OLAP每次操作所需要处理的数据量通常都是非常大的,这点也和OLTP相反。

性能好坏的重要指标:查询大量数据的速度。

由于OLTP和OLAP是两个不同应用方向,所以在优化数据库时应采取不同的优化策略。

2.内存分配比例:2:1:1

内存分配的较佳方案:SGA占50%的物理内存,PGA和操作系统各占25%的物理内存,当然这也不是绝对的

,但是SGA占的物理内存不能超过75%,最多只能占70%,否则Oracle可能会出现各种的异常。

3.SGA中各个POOL的内存分配

(1)Shared Pool:要分配多少内存不定,只要满足以下两个条件即可:

-Lib Cache的命中率>98%

-Data Dictionary Cache的命中率>85%

(2)Large Pool

-专用服务器:100-200M

-共享服务器:Session * (Sort_area_size + 2)

(3)Java Pool:无需使用,一般不分配空间。

(4)Redo Log Buffer Cache:小于5M,因为它的信息非常重要,应尽快把缓存数据写到文件中。

(5)DB_Buffer_Cache:尽量大。

4.在Oracle 10g中,如果我们定义了SGA_MAX_SIZE后,其实我们通过SGA_TARGET让Oracle自动调整SGA的

内存分配。

5.Redo log files,Data files,Archive log files尽量放在不同的磁盘上,以均衡I/O。特别是Redo 

Log files和Archive log files。

6.Undo Segment容量大小要符合实际应用,不能太小。

7.热点文件特殊处理

(1)分开存放Index Segment和Data Segment。

(2)使用分区表。

8.索引(Index)问题

(1)适当使用BTREE,BITMAP以及反向索引:不同索引适用于不同的表,设置索引之前要考虑这个问题



(2)一个表的索引数最多不要超过5个,否则可能影响性能。

(3)定期重构索引。(单边树索引重构时可考虑使用反向索引降低索引树高度)

(4)注意索引是否失效,这一般是比较烂的SQL语句引起的问题。

9.尽量减少“全表扫描操作” & “排序操作”

10.看执行计划有助于各位DBA找出性能问题。

四.SQL语句优化

1.通过v$librarycache了解命中率,这和3.1中提到的Shared Pool有关系,避免重复解析SQL语句,有助

于提高数据库性能。

2.使用“物化视图”提高查询性能。

========

oracle 性能优化建议小结

平时关注Oracle数据库的网友都知道,Oracle性能优化保证了Oracle数据库的健壮性。下面就此提出需

要注意的两个原则。

..原则一:注意WHERE子句中的连接顺序: 

ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 

那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. 

尤其是“主键ID=?”这样的条件。 

原则二: SELECT子句中避免使用 ‘ * ‘: 

ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意

味着将耗费更多的时间 。 

简单地讲,语句执行的时间越短越好(尤其对于系统的终端用户来说)。而对于查询语句,由于全表扫

描读取的数据多,尤其是对于大型表不仅查询速度慢,而且对磁盘IO造成大的压力,通常都要避免,而

避免的方式通常是使用索引Index。 

使用索引的优势与代价。

优势:

1)索引是表的一个概念部分,用来提高检索数据的效率,ORACLE使用了一个复杂的自平衡B-tree结构. 

通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优

化器将使用索引. 同样在联结多个表时使用索引也可以提高效率.

2) 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.。那些LONG或LONG RAW数据类

型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现, 在扫描小表时

,使用索引同样能提高效率.

代价: 虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来存储,也

需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的

INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那

些不必要的索引反而会 使查询反应时间变慢.。而且表越大,影响越严重。 

使用索引需要注意的地方:

1、避免在索引列上使用NOT ,  

我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇

到”NOT,他就会停止使用索引转而执行全表扫描.

2、避免在索引列上使用计算. 

WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描. 举例: 

代码如下:

低效:SELECT … FROM DEPT WHERE SAL * 12 > 25000; 

高效:SELECT … FROM DEPT WHERE SAL > 25000/12;

3、避免在索引列上使用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; 

4、注意通配符%的影响 

使用通配符的情况下Oracle可能会停用该索引。如 : 

代码如下:

SELECT…FROM DEPARTMENT WHERE DEPT_CODE like ‘%123456%'(无效)。 

SELECT…FROM DEPARTMENT WHERE DEPT_CODE = ‘123456'(有效) 

5、避免改变索引列的类型.: 

当比较不同数据类型的数据时, 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会优先转换数值类

型到字符类型 

6、索引的一些“脾气” 

a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高. 

b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别. 而通常情况下,使用

索引比全表扫描要块几倍乃至几千倍! 

除了使用索引,我们还有其他能减少资源消耗的方法:

1、用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 

And E.sex =man 

(高效): SELECT DEPT_NO,DEPT_NAME FROM DEPT D 

WHERE EXISTS 

( SELECT ‘X' FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO 

And E.sex =man 

); 

2、用(UNION)UNION ALL替换OR (适用于索引列) 

通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 

注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR

而降低. 在下面的例子中, LOC_ID 和REGION上都建有索引. 

如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面. 

代码如下:

高效: SELECT LOC_ID , LOC_DESC , REGION FROM LOCATION WHERE LOC_ID = 10 UNION ALL 

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” 

3、用UNION-ALL 替换UNION ( 如果有可能的话): 

当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最

终结果前进行排序. 如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高. 需

要注意的是,UNION ALL 将重复输出两个结果集合中相同记录. 因此各位还是要从业务需求分析使用

UNION ALL的可行性. UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这块

内存的优化也是相当重要的. 

4、Order By语句加在索引列,最好是主键PK上。 

代码如下:

SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE(低效) 

SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_CODE (高效) 

5、避免使用耗费资源的操作: 

带有DISTINCT,UNION,MINUS,INTERSECT的SQL语句会启动SQL引擎 执行耗费资源的排序(SORT)功能. 

DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序. 通常, 带有UNION, MINUS , INTERSECT

的SQL语句都可以用其他方式重写. 如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, 

INTERSECT也是可以考虑的, 毕竟它们的可读性很强 

6、使用Where替代Having(如果可以的话) 

优化GROUP BY: 

提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个查询返回相同结

果但第二个明显就快了许多. 

代码如下:

低效: 

SELECT JOB , AVG(SAL) 

FROM EMP GROUP JOB HAVING JOB = ‘PRESIDENT'AND AVG(SAL)>XXX 

高效: 

SELECT JOB , AVG(SAL) 

FROM EMP 

WHERE JOB = ‘PRESIDENT' 

OR JOB = ‘MANAGER' GROUP JOB Having AND AVG(SAL)>XXX 

7、通常来说,如果语句能够避免子查询的 使用,就尽量不用子查询。因为子查询的开销是相当昂贵的

。具体的例子在后面的案例“一条SQL的优化过程”中。 

如果你还有什么有关Oracle性能提升的建议可以到网站上的论坛里交流。

========

Oracle 查询优化的基本准则详解

1:在进行多表关联时,多用 Where 语句把单个表的结果集最小化,多用聚合函数汇总结果集后再与其

它表做关联,以使结果集数据量最小化

2:在两张表进行关联时,应考虑可否使用右连接。以提高查询速度

3:使用 where 而不是 having ,where是用于过滤行的,而having是用来过滤组的,因为行被分组后,

having 才能过滤组,所以尽量用户 WHERE 过滤

4:使用 exists 而不用 IN 因为 Exists 只检查行的存在,而 in 检查实际值。

5:IN操作符

用 IN 写出来的 SQL 的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。

但是用 IN 的 SQL 性能总是比较低,原因是:

对于用 IN 的 SQL 语句 ORACLE 总是试图将其转换成多个表的连接,如果转换不成功则先执行 IN

里面的子查询,再查询外层的表记录

如果转换成功就转换成多个表的连接。因此 不管理怎么,用 IN 的 SQL 语句总是多了 一个转换的

过程。一般的 SQL 都可以转换成功。

但对于含有分组统计等方面的 SQL 就不能转换了。因此在业务密集的SQL当中尽量不采用IN操作符。

6:NOT IN 操作符

此操作强烈推荐不使用,因为其不能应用表的索引。

如遇这种情况,应该用 EXISTS ,NOT EXISTS 或者(外连接+判断为空)方案代替。

7:<> 操作符

不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。

对于这种情况,可以用其它方式代替,如:

A<>0 -> A>0 OR A<0

A<>'' -> A>''

8:like 操作符

遇到 需要用到 LIKE 过滤的SQL语句,完全可以用 instr 代替。处理速度将显著提高。

9:union操作符

union在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,

删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史

表union。如:

代码如下:

select * from gc_dfys

union

select * from ls_jg_dfys

这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,

如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用union ALL操作符替代union,因为union ALL操作只是简单的将两个结果合并后就返回。

代码如下:

select * from gc_dfys

union all

select * from ls_jg_dfys

10 SQL书写的影响

同一功能同一性能不同写法SQL的影响

如一个SQL在A程序员写的为

select * from zl_yhjbqk

B程序员写的为

select * from dlyx.zl_yhjbqk(带表所有者的前缀)

C程序员写的为

select * from DLYX.ZLYHJBQK(大写表名)

D程序员写的为

select *  from DLYX.ZLYHJBQK(中间多了空格)

以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的

原理,

可以得出ORACLE对每个SQL都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写

得完全相同则ORACLE只会分析一次,

共享内存也只会留下一次的分析结果,这不仅可以减少分析SQL的时间,而且可以减少共享内存重复的

信息,ORACLE也可以准确统计SQL的执行频率。

11:where后面的条件顺序影响

where子句后面的条件顺序对大数据量表的查询会产生直接的影响,如 

代码如下:

select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1

select * from zl_yhjbqk where xh_bz=1  and dy_dj = '1KV以下'

以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都

是全表扫描,

第一条SQL的dy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,

在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录

都进行dy_dj及xh_bz的比较, 

以此可以得出第二条SQL的CPU占用率明显比第一条低。

12:询表顺序的影响

在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的

情况下ORACLE会按表出现的顺序进行链接,

由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析,

ORACLE会自动先进小表的链接,再进行大表的链接)

13:采用函数处理的字段不能利用索引,如:

复制代码 代码如下:

substr(hbs_bh,1,4)='5400',优化处理:hbs_bh like ‘5400%' 

trunc(sk_rq)=trunc(sysdate),优化处理:

sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)

进行了显式或隐式的运算的字段不能进行索引,如:

代码如下:

ss_df+20>50,优化处理:ss_df>30

‘X'||hbs_bh>'X5400021452',优化处理:hbs_bh>'5400021542' 

sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5

hbs_bh=5401002554,优化处理:hbs_bh=' 5401002554',注:此条件对hbs_bh 进行隐式的

to_number转换,因为hbs_bh字段是字符型。 

条件内包括了多个本表的字段运算时不能进行索引,如:

ys_df>cx_df,无法进行优化 

qc_bh||kh_bh='5400250000',优化处理:qc_bh='5400' and kh_bh='250000'

14:应用ORACLE的HINT(提示)处理

提示处理是在ORACLE产生的SQL分析执行路径不满意的情况下要用到的。它可以对SQL进行以下方

面的提示 

目标方面的提示: 

COST(按成本优化)

RULE(按规则优化)

CHOOSE(缺省)(ORACLE自动选择成本或规则进行优化)

SELECT EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

ALL_ROWS(所有的行尽快返回)

SELECT EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

FIRST_ROWS(第一行数据尽快返回)

select *

  from xxx  

 where xxx;

select * 

  from xxx 

 where xxx 

优化器提示:用它的目的是提高SQL语句的响应时间,快速的先返回 n 行。

访问路径的提示

FULL: 执行全表扫描

ROID: 根据ROWID进行扫描

INDEX: 根据某个索引进行扫描

select * from emp where deptno=200 and sal>300;

如果写了多个,则ORACLE自动选择最优的哪个

select * from emp where deptno=200 and sal>300;

INDEX_JOIN: 如果所选的字段都是索引字段(是几个索引的),那么可以通过索引连接就可访问到数据,

而不需要访问

表的数据。

select deptno,sal from emp

where deptno=20; 

INDEX_FFS: 执行快速全索引扫描 

select count(*) from emp;

NO_INDEX: 指定不使用哪些索引

select * from emp where deptno=200

and sal>300;

AND_EQUAL: 指定合并两个或以上索引检索的结果(交集),最多不能超过5个

执行方法的提示: 

USE_NL(使用NESTED LOOPS方式联合) 

USE_MERGE(使用MERGE join方式联合)

USE_HASH(使用HASH join方式联合)

根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.

例如:

SELECT A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C

WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;

将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表. 

例如:

SELECT BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM

FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

将指定的表与其他行源通过合并排序连接方式连接起来.

例如:

SELECT * FROM BSEMPMS,BSDPTMS

WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

将指定的表与其他行源通过哈希连接方式连接起来.

例如:

SELECT * FROM BSEMPMS,BSDPTMS

WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;  

其它高级提示(如并行处理等等)

ORACLE的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给ORACLE执行的一个建议, 

有时如果出于成本方面的考虑ORACLE也可能不会按提示进行。根据实践应用,一般不建议开发人员应用

ORACLE提示,

因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了,

ORACLE在SQL执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)



服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分

析。

========

Oracle优化专题链接

http://sishuok.com/forum/blogPost/list/6413.html

2年资深DBA教你Oracle开发与优化
http://blog.itpub.net/29119536/viewspace-1138006/
oracle优化常用经典参考
http://database.51cto.com/art/201001/181249.htm
Oracle数据库调试与性能优化
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息