Oracle SQL性能优化的40条军规文档格式.docx

上传人:b****4 文档编号:6761967 上传时间:2023-05-07 格式:DOCX 页数:21 大小:23.79KB
下载 相关 举报
Oracle SQL性能优化的40条军规文档格式.docx_第1页
第1页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第2页
第2页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第3页
第3页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第4页
第4页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第5页
第5页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第6页
第6页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第7页
第7页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第8页
第8页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第9页
第9页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第10页
第10页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第11页
第11页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第12页
第12页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第13页
第13页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第14页
第14页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第15页
第15页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第16页
第16页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第17页
第17页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第18页
第18页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第19页
第19页 / 共21页
Oracle SQL性能优化的40条军规文档格式.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Oracle SQL性能优化的40条军规文档格式.docx

《Oracle SQL性能优化的40条军规文档格式.docx》由会员分享,可在线阅读,更多相关《Oracle SQL性能优化的40条军规文档格式.docx(21页珍藏版)》请在冰点文库上搜索。

Oracle SQL性能优化的40条军规文档格式.docx

/*选择TAB2作为基础表(不佳的方法)*/

selectcount(*)fromtab2,tab1执行时间26.09秒

如果有3个以上的表连接查询,那就需要选择交叉表(intersectiontable)作为基础表,交叉表是指那个被其他表所引用的表。

SELECT*FROMLOCATIONL,CATEGORYC,EMPE

WHEREE.EMP_NOBETWEEN1000AND2000

ANDE.CAT_NO=C.CAT_NO

ANDE.LOCN=L.LOCN

将比下列SQL更有效率

SELECT*FROMEMPE,LOCATIONL,CATEGORYC

WHEREE.CAT_NO=C.CAT_NO

ANDE.EMP_NOBETWEEN1000AND2000

6.Where子句中的连接顺序

Oracle采用自下而上的顺序解析WHERE子句。

根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。

/*低效,执行时间156.3秒*/

SELECT…

FROMEMPE

WHERESAL>

50000

ANDJOB=‘MANAGER’

AND25<

(SELECTCOUNT(*)FROMEMP

WHEREMGR=E.EMPNO)

/*高效,执行时间10.6秒*/

WHERE25<

WHEREMGR=E.EMPNO)

ANDSAL>

7.SELECT子句中避免使用“*”

Oracle在解析SQL语句的时候,对于“*”将通过查询数据库字典来将其转换成对应的列名。

如果在Select子句中需要列出所有的Column时,建议列出所有的Column名称,而不是简单的用“*”来替代,这样可以减少多于的数据库查询开销。

8.减少访问数据库的次数

当执行每条SQL语句时,ORACLE在内部执行了许多工作:

解析SQL语句>

估算索引的利用率>

绑定变量>

读数据块等等

由此可见,减少访问数据库的次数,就能实际上减少ORACLE的工作量。

9.整个简单无关联的数据库访问

如果有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系),以减少多于的数据库IO开销。

虽然采取这种方法,效率得到提高,但是程序的可读性大大降低,所以还是要权衡之间的利弊。

10.使用Truncate而非Delete

Delete表中记录的时候,Oracle会在Rollback段中保存删除信息以备恢复。

Truncate删除表中记录的时候不保存删除信息,不能恢复。

因此Truncate删除记录比Delete快,而且占用资源少。

删除表中记录的时候,如果不需要恢复的情况之下应该尽量使用Truncate而不是Delete。

Truncate仅适用于删除全表的记录。

11.尽量多使用COMMIT

只要有可能,在程序中尽量多使用COMMIT,这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少。

COMMIT所释放的资源:

回滚段上用于恢复数据的信息.

被程序语句获得的锁

redologbuffer中的空间

ORACLE为管理上述3种资源中的内部花费

12.计算记录条数

Selectcount(*)fromtablename;

Selectcount

(1)fromtablename;

Selectmax(rownum)fromtablename;

一般认为,在没有索引的情况之下,第一种方式最快。

如果有索引列,使用索引列当然最快。

13.用Where子句替换Having子句

避免使用HAVING子句,HAVING只会在检索出所有记录之后才对结果集进行过滤。

这个处理需要排序、总计等操作。

如果能通过WHERE子句限制记录的数目,就能减少这方面的开销。

14.减少对表的查询操作

在含有子查询的SQL语句中,要注意减少对表的查询操作。

低效:

SELECTTAB_NAMEFROMTABLES

WHERETAB_NAME=(SELECTTAB_NAME

FROMTAB_COLUMNS

WHEREVERSION=604)

ANDDB_VER=(SELECTDB_VER

WHEREVERSION=604)

高效:

WHERE(TAB_NAME,DB_VER)=

(SELECTTAB_NAME,DB_VER

15.使用表的别名(Alias)

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。

Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属。

16.用EXISTS替代IN

在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。

在这种情况下,使用EXISTS(或NOTEXISTS)通常将提高查询的效率。

SELECT*FROMEMP(基础表)

WHEREEMPNO>

0

ANDDEPTNOIN(SELECTDEPTNO

FROMDEPT

WHERELOC=‘MELB’)

ANDEXISTS(SELECT‘X’

WHEREDEPT.DEPTNO=EMP.DEPTNO

ANDLOC=‘MELB’)

17.用NOTEXISTS替代NOTIN

在子查询中,NOTIN子句将执行一个内部的排序和合并,对子查询中的表执行一个全表遍历,因此是非常低效的。

为了避免使用NOTIN,可以把它改写成外连接(OuterJoins)或者NOTEXISTS。

SELECT…

FROMEMP

WHEREDEPT_NONOTIN(SELECTDEPT_NO

WHEREDEPT_CAT=’A’)

SELECT….

WHERENOTEXISTS(SELECT‘X’

FROMDEPTD

WHERED.DEPT_NO=E.DEPT_NO

ANDDEPT_CAT=‘A’)

18.用表连接替换EXISTS

通常来说,采用表连接的方式比EXISTS更有效率。

SELECTENAME

WHEREEXISTS(SELECT‘X’

FROMDEPT

WHEREDEPT_NO=E.DEPT_NO

FROMDEPTD,EMPE

WHEREE.DEPT_NO=D.DEPT_NO

ANDDEPT_CAT=‘A’

19.用EXISTS替换DISTINCT

当提交一个包含对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT。

一般可以考虑用EXIST替换。

EXISTS使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果。

SELECTDISTINCTDEPT_NO,DEPT_NAME

SELECTDEPT_NO,DEPT_NAME

WHEREEXISTS(SELECT‘X’

WHEREE.DEPT_NO=D.DEPT_NO

20.识别低效的SQL语句

下面的SQL工具可以找出低效SQL:

SELECTEXECUTIONS,DISK_READS,BUFFER_GETS,

ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2)Hit_radio,

ROUND(DISK_READS/EXECUTIONS,2)Reads_per_run,

SQL_TEXT

FROMV$SQLAREA

WHEREEXECUTIONS>

ANDBUFFER_GETS>

0

AND(BUFFER_GETS-DISK_READS)/BUFFER_GETS<

0.8

ORDERBY4DESC

另外也可以使用SQLTrace工具来收集正在执行的SQL的性能状态数据,包括解析次数,执行次数,CPU使用时间等。

21.用ExplainPlan分析SQL语句

EXPLAINPLAN是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句.通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称。

22.SQLPLUS的TRACE

SQL>

list

1SELECT*

2FROMdept,emp

3*WHEREemp.deptno=dept.deptno

setautotracetraceonly/*traceonly可以不显示执行结果*/

/

14rowsselected.

ExecutionPlan

----------------------------------------------------------

0SELECTSTATEMENTOptimizer=CHOOSE

10NESTEDLOOPS

21TABLEACCESS(FULL)OF'

EMP'

31TABLEACCESS(BYINDEXROWID)OF'

DEPT'

43INDEX(UNIQUESCAN)OF'

PK_DEPT'

(UNIQUE)

23.用索引提高效率

(1)特点

优点:

提高效率主键的唯一性验证

代价:

需要空间存储定期维护

重构索引:

ALTERINDEX<

INDEXNAME>

REBUILD<

TABLESPACENAME>

(2)Oracle对索引有两种访问模式

索引唯一扫描(IndexUniqueScan)

索引范围扫描(IndexRangeScan)

(3)基础表的选择

基础表(DrivingTable)是指被最先访问的表(通常以全表扫描的方式被访问)。

根据优化器的不同,SQL语句中基础表的选择是不一样的。

如果你使用的是CBO(COSTBASEDOPTIMIZER),优化器会检查SQL语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径。

如果你用RBO(RULEBASEDOPTIMIZER),并且所有的连接条件都有索引对应,在这种情况下,基础表就是FROM子句中列在最后的那个表。

(4)多个平等的索引

当SQL语句的执行路径可以使用分布在多个表上的多个索引时,ORACLE会同时使用多个索引并在运行时对它们的记录进行合并,检索出仅对全部索引有效的记录。

在ORACLE选择执行路径时,唯一性索引的等级高于非唯一性索引。

然而这个规则只有当WHERE子句中索引列和常量比较才有效。

如果索引列和其他表的索引类相比较。

这种子句在优化器中的等级是非常低的。

如果不同表中两个相同等级的索引将被引用,FROM子句中表的顺序将决定哪个会被率先使用。

FROM子句中最后的表的索引将有最高的优先级。

如果相同表中两个相同等级的索引将被引用,WHERE子句中最先被引用的索引将有最高的优先级。

(5)等式比较优先于范围比较

DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引。

WHEREDEPTNO>

20

ANDEMP_CAT=‘A’;

这里只有EMP_CAT索引被用到,然后所有的记录将逐条与DEPTNO条件进行比较.执行路径如下:

TABLEACCESSBYROWIDONEMP

INDEXRANGESCANONCAT_IDX

即使是唯一性索引,如果做范围比较,其优先级也低于非唯一性索引的等式比较。

(6)不明确的索引等级

当ORACLE无法判断索引的等级高低差别,优化器将只使用一个索引,它就是在WHERE子句中被列在最前面的。

ANDEMP_CAT>

‘A’;

这里,ORACLE只用到了DEPT_NO索引.执行路径如下:

INDEXRANGESCANONDEPT_IDX

(7)强制索引失效

如果两个或以上索引具有相同的等级,你可以强制命令ORACLE优化器使用其中的一个(通过它,检索出的记录数量少)。

FROMEMP

WHEREEMPNO=7935

ANDDEPTNO+0=10/*DEPTNO上的索引将失效*/

ANDEMP_TYPE||‘’=‘A’/*EMP_TYPE上的索引将失效*/

(8)避免在索引列上使用计算

WHERE子句中,如果索引列是函数的一部分。

优化器将不使用索引而使用全表扫描。

WHERESAL*12>

25000;

25000/12;

(9)自动选择索引

如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性索引。

在这种情况下,ORACLE将使用唯一性索引而完全忽略非唯一性索引。

WHEREEMPNO=2326

ANDDEPTNO=20;

这里,只有EMPNO上的索引是唯一性的,所以EMPNO索引将用来检索记录。

INDEXUNIQUESCANONEMP_NO_IDX

(10)避免在索引列上使用NOT

通常,我们要避免在索引列上使用NOT,NOT会产生在和在索引列上使用函数相同的影响。

当ORACLE遇到NOT,它就会停止使用索引转而执行全表扫描。

低效:

(这里,不使用索引)

SELECT…

WHERENOTDEPT_CODE=0

(这里,使用了索引)

WHEREDEPT_CODE>

24.用>

=替代>

如果DEPTNO上有一个索引

高效:

SELECT*

=4

3

两者的区别在于,前者DBMS将直接跳到第一个DEPT等于4的记录,而后者将首先定位到DEPTNO等于3的记录并且向前扫描到第一个DEPT大于3的记录.

25.用Union替换OR(适用于索引列)

通常情况下,用UNION替换WHERE子句中的OR将会起到较好的效果。

对索引列使用OR将造成全表扫描。

注意,以上规则只针对多个索引列有效。

SELECTLOC_ID,LOC_DESC,REGION

FROMLOCATION

WHERELOC_ID=10

UNION

SELECTLOC_ID,LOC_DESC,REGION

WHEREREGION=“MELBOURNE”

WHERELOC_ID=10ORREGION=“MELBOURNE”

26.用IN替换OR

SELECT….

WHERELOC_ID=10

ORLOC_ID=20

ORLOC_ID=30

SELECT…

WHERELOC_ININ(10,20,30)

实际的执行效果还须检验,在ORACLE8i下,两者的执行路径似乎是相同的。

27.避免在索引列上使用isnull和isnotnull

避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引。

(索引失效)

FROMDEPARTMENT

WHEREDEPT_CODEISNOTNULL;

(索引有效)

WHEREDEPT_CODE>

=0;

28.总是使用索引的第一个列

如果索引是建立在多个列上,只有在它的第一个列(leadingcolumn)被where子句引用时,优化器才会选择使用该索引。

createindexmultindexonmultiindexusage(inda,indb);

Indexcreated.

select*frommultiindexusagewhereindb=1;

10TABLEACCESS(FULL)OF'

MULTIINDEXUSAGE‘

很明显,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引。

29.使用UNIONALL替代UNION

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

如果用UNIONALL替代UNION,这样排序就不是必要了,效率就会因此得到提高。

由于UNIONALL的结果没有经过排序,而且不过滤重复的记录,因此是否进行替换需要根据业务需求而定。

30.对UNION的优化

由于UNION会对查询结果进行排序,而且过滤重复记录,因此其执行效率没有UNIONALL高。

UNION操作会使用到SORT_AREA_SIZE内存块,因此对这块内存的优化也非常重要。

可以使用下面的SQL来查询排序的消耗量:

selectsubstr(name,1,25)"

SortAreaName"

substr(value,1,15)"

Value"

fromv$sysstat

wherenamelike'

sort%'

31.避免改变索引列的类型

当比较不同数据类型的数据时,ORACLE自动对列进行简单的类型转换。

/*假设EMP_TYPE是一个字符类型的索引列.*/

WHEREEMP_TYPE=123

/*这个语句被ORACLE转换为:

*/

WHERETO_NUMBER(EMP_TYPE)=123

因为内部发生的类型转换,这个索引将不会被用到。

几点注意:

当比较不同数据类型的数据时,ORACLE自动对列进行简单的类型转换。

如果在索引列上面进行了隐式类型转换,在查询的时候将不会用到索引。

注意当字符和数值比较时,ORACLE会优先转换数值类型到字符类型。

为了避免ORACLE对SQL进行隐式的类型转换,最好把类型转换用显式表现出来。

32.使用提示(Hints)

FULLhint告诉ORACLE使用全表扫描的方式访问指定表。

ROWIDhint告诉ORACLE使用TABLEACCESSBYROWID的操作访问表。

CACHEhint来告诉优化器把查询结果数据保留在SGA中。

INDEXHint告诉ORACLE使用基于索引的扫描方式。

其他的OracleHints

ALL_ROW

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2