Oracle_SQL性能优化技巧大总结

合集下载

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可能会停⽤该索引。

oracle优化方法总结

oracle优化方法总结

千里之行,始于足下。

oracle优化方法总结Oracle优化是提高数据库性能和响应能力的重要步骤。

本文总结了一些常见的Oracle优化方法。

1. 使用索引:索引是提高查询性能的主要方法。

通过在表中创建适当的索引,可以加快查询速度,并减少数据访问的开销。

但是要注意不要过度使用索引,因为过多的索引会增加写操作的开销。

2. 优化查询语句:查询语句的效率直接影响数据库的性能。

可以通过合理地编写查询语句来提高性能。

例如,使用JOIN来替代子查询,尽量避免使用通配符查询,使用LIMIT来限制结果集的大小等。

3. 优化表结构:表的设计和结构对数据库的性能也有很大的影响。

合理的表设计可以减少数据冗余和不必要的数据存储,提高查询速度。

例如,适当地使用主键、外键和约束,避免过多的数据类型和字段等。

4. 优化数据库参数设置:Oracle有很多参数可以用来调整数据库的性能。

根据具体的应用场景和需求,可以根据情况调整参数的值。

例如,调整SGA和PGA的大小,设置合适的缓冲区大小,调整日志写入方式等。

5. 使用分区表:当表的数据量很大时,可以考虑将表分成多个分区。

分区表可以加速查询和维护操作,提高数据库的性能。

可以按照时间、地域、业务等来进行分区。

6. 优化存储管理:Oracle提供了多种存储管理选项,如表空间和数据文件管理。

合理地分配存储空间和管理数据文件可以提高数据库的性能。

例如,定期清理无用的数据文件,使用自动扩展表空间等。

第1页/共2页锲而不舍,金石可镂。

7. 数据压缩:对于大量重复数据或者冷数据,可以考虑使用Oracle的数据压缩功能。

数据压缩可以减少磁盘空间的使用,提高IO性能。

8. 使用并行处理:对于大型计算或者批处理任务,可以考虑使用Oracle的并行处理功能。

并行处理可以将任务分成多个子任务,并行执行,提高处理能力和效率。

9. 数据库分区:对于大型数据库,可以考虑将数据库分成多个独立的分区。

数据库分区可以提高数据的并行处理能力,减少锁竞争和冲突,提高数据库的性能。

Oracle SQL语句优化技术分析

Oracle SQL语句优化技术分析
4 结 论
O a e S L 句的性 能问题 常常是 由于 rl Q 语 c 在索引设计和查询设计方面存在各种缺陷引起 的。 Q 优化的实质就是在结果正确的前提下 , SL 充份利用索引 , 减少表扫描的 I / O次数 , 尽量避 免表搜索的发生 。 其实 S L Q 的性能优 化是一个 复杂的过程 ,以上这些只是在应用层次 的一种 体现 , 深入研究还会涉及数据库层 的资源配置 、 网络层的流量控制 以及操作系统层 的总体设计 如 等等方面 , 已经超 出本文所要讨论 的范 围, 这些 S EC EL T FROM US ER LOG WHER 因此不在本文赘述 了。 E 总之 Oal S L语句 的 r e Q c USE N R AME ei ( L C U E _ A 不断总结 , 才 xs t S E T S R N ME 优化需要我们在生产 中不断学习 , E FROM T F W HE TY C D =05 ' S AF E R CI 能更为得心应手 的应用到工作中去。 O E ' 1 4 3 O N操作符 . N TI 2 此操作是 强列不推荐使用 的 , 因为它不能
的 ,因为索引是不索引空值的。使用 I N L SU 或 I O U ,r l会停止使用 索引而执 SN TN L Oa e c 行 全表扫描。 以考虑在设计表时 , 引列设 可 对索 置为 N T N L 。这样就可以用其他操作来取 O U L 代 判断 N L 的操作。 UL
_
b .同一功能 同一性能 不同写法 S QL的影 响。 如一个 S L在 A程序员写的为 slc S Q eetU— e a ,s d f m s fB程序员写 的为 s—  ̄nme e r t u o a e le s r n meu e i f m zj s ( e t u e a . s r d r h .a 带表所有 o st f 者的前缀 )c程序员写的为 Sl tu rn n, e c s_s e e e z u ser i f m Z J . A F ( 写表名 )D程序 d r HS T F 大 o S 员 写 的 为 Slc srnme sri f m e et e_a , e_d r u u o z SS A F 中间多 了空格 )以上 四个 S L在 Ⅲ . F( T Q OAL R C E分析整理之后产生的结果及执行的时

ORACLE数据库性能优化

ORACLE数据库性能优化

(三)(三)优化 I/O 操作 I/O 优化被安排在内存优化之后,通过内存的优化,可以是 I/O 冲突减少,在此情况下, 可以通过一些调整以使 I/O 性能进一步提高。 对于新系统,应自顶向下分析 I/O 需求,确定所需要的资源。而对于已存在的系统应采 用自底向上的方法: 1.1.了解系统的磁盘数量。 2.2.了解 ORACLE 使用的磁盘数量。 3.3.了解应用系统的 I/O 类型。 4.4.了解 I/O 操作是针对文件系统还是原始设备。 5.5.了解对象在磁盘上的分布。 可以通过如下方法检查 I/O 问题: 检查系统 I/O 的使用:可以使用操作系统提供的工具来监视整个系统对磁盘 文件的访问,可以将大量访问磁盘的应用与 ORACLE 的相关文件分别存放。在 UNIX 系统中可以通过 sar –d 来获得有关数据。在 WINDOWS NT 中 可 通 过 性 能监视器查看。 检查 ORACLE 的 I/O 的使用:对于 ORACLE ,可以通过下列视图来获得相 关的信息: File Type Where to Find Statistics Database Files V$FILESTAT Log Files V$SYSSTAT, V$SYSTEM_EVENT, V$SESSION_EVENT Archive Files V$SYSTEM_EVENT, V$SESSION_EVENT Control Files V$SYSTEM_EVENT, V$SESSION_EVENT 可以通过如下的方法来解决 I/O 问题: 减少磁盘竞争: 磁盘竞争:当多个进程同时访问同一个磁盘时就会产生磁盘竞争。要减 少高负荷磁盘的访问,可以将高访问量的文件移到低负荷的磁盘上。 分离 Redo 日志文件和数据文件:ORACLE 总是经常的访问 Redo 日志 文件和数据文件,将二者放在一起,可能会增加磁盘冲突。 条带化表数据:条带化,就是将一个大表的数据分布到不同磁盘的不同 数据文件中,这样也可以减少磁盘冲突。 分离表和索引:这并不是必须的,由于索引和表的读取是串行的,也可 以做到将表和索引放在一起而不发生磁盘冲突。 磁盘条带化:就是将一个大表的数据分布到不同磁盘的不同数据文件中,条 带化允许不同的进程同时访问一个表的不同部分。 这尤其对随机访问一个表的多行 很有帮助。条带化可以是磁盘的 I/O 负载平衡。有两种条带化方法。 手动方法:利用表空间以及分区表的方式。

Oracle性能优化学习心得

Oracle性能优化学习心得

Oracle性能优化学习心得一,优化总的原那么1,查看系统的利用情形2,查看SGA分派情形,结合系统具体情形进行分析。

3,表的设计分析4,SQL语句分析实施要那么1,查看系统的利用情形,CPU占用,内存,I/O读取等Oracle10G提供的Oracle Enterprise Manager图形化工具中的ADDM 和 SQL Tuning Advisor等能够方便的查看系统状况2,OPS上负载均衡,不同查询用不同Instance3,提供脚本查看SGA利用情形4,分析SQL执行情形(trace及其他工具)实施细节1,外部调整:咱们应该记住Oracle并非是单独运行的。

因此咱们将查看一下通过调整Oracle效劳器以取得高的性能。

2,Row re-sequencing以减少磁盘I/O:咱们应该知道Oracle调优最重要的目标是减少I/O。

3,Oracle SQL调整。

Oracle SQL调整是Oracle调整中最重要的领域之一,只要通过一些简单的SQL调优规那么就能够够大幅度地提升SQL语句的性能,这是一点都不奇怪的。

4,调整Oracle排序:排序关于Oracle性能也是有专门大阻碍的。

5,调整Oracle的竞争:表和索引的参数设置关于UPDATE和INSERT的性能有专门大的阻碍。

二,调优分类:对Oracle数据库进行性能调整时,应当依照必然的顺序进行,因为系统在前面步骤中进行的调整能够幸免后面的一些没必要要调整或代价专门大的调整。

一样来讲能够从两个时期入手:一、设计时期:对其逻辑结构和物理结构进行优化设计,使之在知足需求条件的情形下,系统性能达到最正确,系统开销达到最小;二、数据库运行时期:采取操作系统级、数据库级的一些优化方法来使系统性能最正确;㈠设计时期:A,数据库设计优化较多修改较少查询的数据和较多查询较少修改的数据别离对待。

a,结构优化1,依照应用程序进行数据库设计。

即应用程序采纳的是传统的C/S两层体系结构,仍是B/W/D三层体系结构。

oracle sql 优化技巧

oracle sql 优化技巧

oracle sql 优化技巧(实用版3篇)目录(篇1)1.Oracle SQL 简介2.优化技巧2.1 减少访问数据库次数2.2 选择最有效率的表名顺序2.3 避免使用 SELECT2.4 利用 DECODE 函数2.5 设置 ARRAYSIZE 参数2.6 使用 TRUNCATE 替代 DELETE2.7 多使用 COMMIT 命令2.8 合理使用索引正文(篇1)Oracle SQL 是一款广泛应用于各类大、中、小微机环境的高效、可靠的关系数据库管理系统。

为了提高 Oracle SQL 的性能,本文将为您介绍一些优化技巧。

首先,减少访问数据库的次数是最基本的优化方法。

Oracle 在内部执行了许多工作,如解析 SQL 语句、估算索引的利用率、读数据块等,这些都会大量耗费 Oracle 数据库的运行。

因此,尽量减少访问数据库的次数,可以有效提高系统性能。

其次,选择最有效率的表名顺序也可以明显提升 Oracle 的性能。

Oracle 解析器是按照从右到左的顺序处理 FROM 子句中的表名,因此,合理安排表名顺序,可以减少解析时间,提高查询效率。

在执行 SELECT 子句时,应尽量避免使用,因为 Oracle 在解析的过程中,会将依次转换成列名,这是通过查询数据字典完成的,耗费时间较长。

DECODE 函数也是一个很好的优化工具,它可以避免重复扫描相同记录,或者重复连接相同的表,提高查询效率。

在 SQLPlus 和 SQLForms 以及 ProC 中,可以重新设置 ARRAYSIZE 参数。

该参数可以明显增加每次数据库访问时的检索数据量,从而提高系统性能。

建议将该参数设置为 200。

当需要删除数据时,尽量使用 TRUNCATE 语句替代 DELETE 语句。

执行 TRUNCATE 命令时,回滚段不会存放任何可被恢复的信息,所有数据不能被恢复。

因此,TRUNCATE 命令执行时间短,且资源消耗少。

在使用 Oracle 时,尽量多使用 COMMIT 命令。

oracle_sql_optimize.doc

oracle_sql_optimize.doc

Oracle sql 性能优化调整1. 选用适合的ORACLE优化器ORACLE的优化器共有3种:a. RULE (基于规则)b. COST (基于成本)c. CHOOSE (选择性)设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖.为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze 命令,以增加数据库中的对象统计信息(object statistics)的准确性.如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器.在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器.2.访问Table的方式ORACLE 采用两种访问表中记录的方式:a.全表扫描全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描.b.通过ROWID访问表你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.3.共享SQL语句为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享.因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用.可惜的是ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询.数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,当然被共享的可能性也就越大了.当你向ORACLE 提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句.这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同(包括空格,换行等).共享的语句必须满足三个条件:A.字符级的比较:当前被执行的语句和共享池中的语句必须完全相同.例如:SELECT * FROM EMP;和下列每一个都不同SELECT * from EMP;Select * From Emp;SELECT * FROM EMP;B.两个语句所指的对象必须完全相同:例如:用户对象名如何访问Jack sal_limit private synonymWork_city public synonymPlant_detail public synonymJill sal_limit private synonymWork_city public synonymPlant_detail table owner考虑一下下列SQL语句能否在这两个用户之间共享.C.两个SQL语句中必须使用相同的名字的绑定变量(bind variables)例如:第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值)a.select pin , name from people where pin = :blk1.pin;select pin , name from people where pin = :blk1.pin;b.select pin , name from people where pin = :blk1.ot_ind;select pin , name from people where pin = :blk1.ov_ind;4. 选择最有效率的表名顺序(只在基于规则的优化器中有效)ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理.在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并.例如: 表TAB1 16,384 条记录表TAB2 1 条记录选择TAB2作为基础表(最好的方法)select count(*) from tab1,tab2 执行时间0.96秒选择TAB2作为基础表(不佳的方法)select count(*) from tab2,tab1 执行时间26.09秒如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.例如: EMP表描述了LOCATION表和CATEGORY表的交集.SELECT *FROM LOCATION L ,CATEGORY C,EMP EWHERE E.EMP_NO BETWEEN 1000 AND 2000AND E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCN将比下列SQL更有效率SELECT *FROM EMP E ,LOCATION L ,CATEGORY CWHERE E.CAT_NO = C.CA T_NOAND E.LOCN = L.LOCNAND E.EMP_NO BETWEEN 1000 AND 20005.WHERE子句中的连接顺序.ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.例如:(低效,执行时间156.3秒)SELECT …FROM EMP EWHERE SAL > 50000AND JOB = ‘MANAGER’AND 25 < (SELECT COUNT(*) FROM EMPWHERE MGR=E.EMPNO);(高效,执行时间10.6秒)SELECT …FROM EMP EWHERE 25 < (SELECT COUNT(*) FROM EMPWHERE MGR=E.EMPNO)AND SAL > 50000AND JOB = ‘MANAGER’;6.SELECT子句中避免使用‘ * ‘当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用‘*’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将’*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.7.减少访问数据库的次数当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量, 读数据块等等. 由此可见, 减少访问数据库的次数, 就能实际上减少ORACLE的工作量.例如,以下有三种方法可以检索出雇员号等于0342或0291的职员.方法1 (最低效)SELECT EMP_NAME , SALARY , GRADEFROM EMPWHERE EMP_NO = 342;SELECT EMP_NAME , SALARY , GRADEFROM EMPWHERE EMP_NO = 291;方法2 (次低效)DECLARECURSOR C1 (E_NO NUMBER) ISSELECT EMP_NAME,SALARY,GRADEFROM EMPWHERE EMP_NO = E_NO;BEGINOPEN C1(342);SELECT C1 INTO …,…,…;FETCH C1 INTO …,..,.. ;OPEN C1(291);FETCH C1 INTO …,..,.. ;CLOSE C1;END;方法3 (高效)SELECT A.EMP_NAME , A.SALARY , A.GRADE,B.EMP_NAME , B.SALARY , B.GRADEFROM EMP A,EMP BWHERE A.EMP_NO = 342AND B.EMP_NO = 291;注意:在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量,建议值为200.8.使用DECODE函数来减少处理时间使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.例如:SELECT COUNT(*),SUM(SAL)FROM EMPWHERE DEPT_NO = 0020AND ENAME LIKE‘SMITH%’;SELECT COUNT(*),SUM(SAL)FROM EMPWHERE DEPT_NO = 0030AND 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_SALFROM EMP WHERE ENAME LIKE ‘SMITH%’;类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.9.整合简单,无关联的数据库访问如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)例如:SELECT NAMEFROM EMPWHERE EMP_NO = 1234;SELECT NAMEFROM DPTWHERE DPT_NO = 10 ;SELECT NAMEFROM CATWHERE CAT_TYPE = ‘RD’;上面的3个查询可以被合并成一个:SELECT , , FROM CAT C , DPT D , EMP E,DUAL XWHERE NVL(‘X’,X.DUMMY) = NVL(‘X’,E.ROWID(+))AND NVL(‘X’,X.DUMMY) = NVL(‘X’,D.ROWID(+))AND NVL(‘X’,X.DUMMY) = NVL(‘X’,C.ROWID(+))AND E.EMP_NO(+) = 1234AND D.DEPT_NO(+) = 10AND C.CAT_TYPE(+) = ‘RD’;(译者按: 虽然采取这种方法,效率得到提高,但是程序的可读性大大降低,所以读者还是要权衡之间的利弊)10.删除重复记录最高效的删除重复记录方法( 因为使用了ROWID)DELETE FROM EMP EWHERE E.ROWID > (SELECT MIN(X.ROWID)FROM EMP XWHERE X.EMP_NO = E.EMP_NO);11.用TRUNCATE替代DELETE当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短.(译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)12.尽量多使用COMMIT只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少:COMMIT所释放的资源:a.回滚段上用于恢复数据的信息.b.被程序语句获得的锁c.redo log buffer 中的空间d.ORACLE为管理上述3种资源中的内部花费(译者按: 在使用COMMIT时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼)13.计算记录条数和一般的观点相反, count(*) 比count(1)稍快, 当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如COUNT(EMPNO)(译者按: 在CSDN论坛中,曾经对此有过相当热烈的讨论, 作者的观点并不十分准确,通过实际的测试,上述三种方法并没有显著的性能差别)14.用Where子句替换HA VING子句避免使用HA VING子句, HA VING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.例如:低效:SELECT REGION,A VG(LOG_SIZE)FROM LOCATIONGROUP BY REGIONHA VING REGION REGION != ‘SYDNEY’AND REGION != ‘PERTH’高效SELECT REGION,A VG(LOG_SIZE)FROM LOCATIONW HERE REGION REGION != ‘SYDNEY’AND REGION != ‘PERTH’GROUP BY REGION(译者按: HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中)15.减少对表的查询在含有子查询的SQL语句中,要特别注意减少对表的查询.例如:低效SELECT TAB_NAMEFROM TABLESWHERE TAB_NAME = ( SELECT TAB_NAMEFROM TAB_COLUMNSWHERE VERSION = 604)AND DB_VER= ( SELECT DB_VERFROM TAB_COLUMNSWHERE VERSION = 604)高效SELECT TAB_NAMEFROM TABLESWHERE (TAB_NAME,DB_VER)= ( SELECT TAB_NAME,DB_VER)FROM TAB_COLUMNSWHERE VERSION = 604)Update 多个Column 例子:低效:UPDA TE EMPSET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES), SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CA TEGORIES) WHERE EMP_DEPT = 0020;高效:UPDA TE EMPSET (EMP_CA T, SAL_RANGE)= (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)FROM EMP_CATEGORIES)WHERE EMP_DEPT = 0020;16.通过内部函数提高SQL效率.SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(*)FROM HISTORY_TYPE T,EMP E,EMP_HISTORY HWHERE H.EMPNO = E.EMPNOAND H.HIST_TYPE = T.HIST_TYPEGROUP BY H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC;通过调用下面的函数可以提高效率.FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN V ARCHAR2 ASTDESC V ARCHAR2(30);CURSOR C1 ISSELECT TYPE_DESCFROM HISTORY_TYPEWHERE HIST_TYPE = TYP;BEGINOPEN C1;FETCH C1 INTO TDESC;CLOSE C1;RETURN (NVL(TDESC,’?’));END;FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN V ARCHAR2ASENAME V ARCHAR2(30);CURSOR C1 ISSELECT ENAMEFROM EMPWHERE EMPNO=EMP;BEGINOPEN C1;FETCH C1 INTO ENAME;CLOSE C1;RETURN (NVL(ENAME,’?’));END;SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO),H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*)FROM EMP_HISTORY HGROUP BY H.EMPNO , H.HIST_TYPE;(译者按: 经常在论坛中看到如’能不能用一个SQL写出….’ 的贴子, 殊不知复杂的SQL 往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的)17.使用表的别名(Alias)当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.(译者注: Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属)18.用EXISTS替代IN在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.低效:SELECT *FROM EMP (基础表)WHERE EMPNO > 0AND DEPTNO IN (SELECT DEPTNOFROM DEPTWHERE LOC = ‘MELB’)高效:SELECT *FROM EMP (基础表)WHERE EMPNO > 0AND EXISTS (SELECT *FROM DEPTWHERE DEPT.DEPTNO = EMP.DEPTNOAND LOC = ‘MELB’)(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出) 19.用NOT EXISTS替代NOT IN在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的(因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.例如:SELECT …FROM EMPWHERE DEPT_NO NOT IN (SELECT DEPT_NOFROM DEPTWHERE DEPT_CA T=’A’);为了提高效率.改写为:(方法一: 高效)SELECT ….FROM EMP A,DEPT BWHERE A.DEPT_NO = B.DEPT(+)AND B.DEPT_NO IS NULLAND B.DEPT_CAT(+) = ‘A’(方法二: 最高效)SELECT ….FROM EMP EWHERE NOT EXISTS(SELECT ‘X’FROM DEPT DWHERE D.DEPT_NO = E.DEPT_NOAND DEPT_CAT = ‘A’);20.用表连接替换EXISTS通常来说, 采用表连接的方式比EXISTS更有效率SELECT ENAMEFROM EMP EWHERE EXISTS (SELECT ‘X’FROM DEPTWHERE DEPT_NO = E.DEPT_NOAND DEPT_CAT = ‘A’);(更高效)SELECT ENAMEFROM DEPT D,EMP EWHERE E.DEPT_NO = D.DEPT_NOAND DEPT_CAT = ‘A’ ;(译者按: 在RBO的情况下,前者的执行路径包括FILTER,后者使用NESTED LOOP) 21.用EXISTS替换DISTINCT ????????????????当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换例如:低效:SELECT DISTINCT DEPT_NO,DEPT_NAMEFROM DEPT D,EMP EWHERE D.DEPT_NO = E.DEPT_NO高效:SELECT DEPT_NO,DEPT_NAMEFROM DEPT DWHERE EXISTS ( SELECT ‘X’FROM EMP EWHERE E.DEPT_NO = D.DEPT_NO);EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.22.识别’低效执行’的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_TEXTFROM V$SQLAREAWHERE EXECUTIONS>0AND BUFFER_GETS > 0AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8ORDER BY 4 DESC;(译者按: 虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己的SQL工具来解决问题始终是一个最好的方法)23.使用TKPROF 工具来查询SQL性能状态SQL trace 工具收集正在执行的SQL的性能状态数据并记录到一个跟踪文件中. 这个跟踪文件提供了许多有用的信息,例如解析次数.执行次数,CPU使用时间等.这些数据将可以用来优化你的系统.设置SQL TRACE在会话级别: 有效ALTER SESSION SET SQL_TRACE TRUE设置SQL TRACE 在整个数据库有效仿, 你必须将SQL_TRACE参数在init.ora中设为TRUE, USER_DUMP_DEST参数说明了生成跟踪文件的目录(译者按: 这一节中,作者并没有提到TKPROF的用法, 对SQL TRACE的用法也不够准确, 设置SQL TRACE首先要在init.ora中设定TIMED_STATISTICS, 这样才能得到那些重要的时间状态. 生成的trace文件是不可读的,所以要用TKPROF工具对其进行转换,TKPROF 有许多执行参数. 大家可以参考ORACLE手册来了解具体的配置. )24.用EXPLAIN PLAN 分析SQL语句EXPLAIN PLAN 是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句. 通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称.你需要按照从里到外,从上到下的次序解读分析的结果. EXPLAIN PLAN分析的结果是用缩进的格式排列的, 最内部的操作将被最先解读, 如果两个操作处于同一层中,带有最小操作号的将被首先执行.NESTED LOOP是少数不按照上述规则处理的操作, 正确的执行路径是检查对NESTED LOOP提供数据的操作,其中操作号最小的将被最先处理.译者按:通过实践, 感到还是用SQLPLUS中的SET TRACE 功能比较方便.举例:SQL> list1 SELECT *2 FROM dept, emp3* WHERE emp.deptno = dept.deptnoSQL> set autotrace traceonly /*traceonly 可以不显示执行结果*/ SQL> /14 rows selected.Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 NESTED LOOPS2 1 TABLE ACCESS (FULL) OF 'EMP'3 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'4 3 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)Statistics----------------------------------------------------------0 recursive calls2 db block gets30 consistent gets0 physical reads0 redo size2598 bytes sent via SQL*Net to client503 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)14 rows processed通过以上分析,可以得出实际的执行步骤是:1.TABLE ACCESS (FULL) OF 'EMP'2.INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)3.TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'4.NESTED LOOPS (JOINING 1 AND 3)注: 目前许多第三方的工具如TOAD和ORACLE本身提供的工具如OMS的SQL Analyze 都提供了极其方便的EXPLAIN PLAN工具.也许喜欢图形化界面的朋友们可以选用它们. 25.用索引提高效率索引是表的一个概念部分,用来提高检索数据的效率. 实际上,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.除了那些LONG或LONG RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现, 在扫描小表时,使用索引同样能提高效率.虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.译者按:定期的重构索引是有必要的.ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>26.索引的操作ORACLE对索引有两种访问模式.索引唯一扫描 ( INDEX UNIQUE SCAN)大多数情况下, 优化器通过WHERE子句访问INDEX.例如:表LODGING有两个索引 : 建立在LODGING列上的唯一性索引LODGING_PK 和建立在MANAGER列上的非唯一性索引LODGING$MANAGER.SELECT *FROM LODGINGWHERE LODGING = ‘ROSE HILL’;在内部 , 上述SQL将被分成两步执行, 首先 , LODGING_PK 索引将通过索引唯一扫描的方式被访问 , 获得相对应的ROWID, 通过ROWID访问表的方式执行下一步检索.如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表). 因为检索数据保存在索引中, 单单访问索引就可以完全满足查询结果.下面SQL只需要INDEX UNIQUE SCAN 操作.SELECT LODGINGFROM LODGINGWHERE LODGING = ‘ROSE HILL’;索引范围查询(INDEX RANGE SCAN)适用于两种情况:1.基于一个范围的检索2.基于非唯一性索引的检索例1:SELECT LODGINGFROM LODGINGWHERE LODGING LIKE ‘M%’;WHERE子句条件包括一系列值, ORACLE将通过索引范围查询的方式查询LODGING_PK . 由于索引范围查询将返回一组值, 它的效率就要比索引唯一扫描低一些.例2:SELECT LODGINGFROM LODGINGWHERE MANAGER = ‘BILL GATES’;这个SQL的执行分两步, LODGING$MANAGER的索引范围查询(得到所有符合条件记录的ROWID) 和下一步同过ROWID访问表得到LODGING列的值. 由于LODGING$MANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描.由于SQL返回LODGING列,而它并不存在于LODGING$MANAGER索引中, 所以在索引范围查询后会执行一个通过ROWID访问表的操作.WHERE子句中, 如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始, 索引将不被采用.SELECT LODGINGFROM LODGINGWHERE MANAGER LIKE ‘%HANMAN’;在这种情况下,ORACLE将使用全表扫描.27.基础表的选择基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的.如果你使用的是CBO (COST BASED OPTIMIZER),优化器会检查SQL语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径.如果你用RBO (RULE BASED OPTIMIZER) , 并且所有的连接条件都有索引对应, 在这种情况下, 基础表就是FROM 子句中列在最后的那个表.举例:SELECT , B.MANAGERFROM WORKER A,LODGING BWHERE A.LODGING = B.LODING;由于LODGING表的LODING列上有一个索引, 而且WORKER表中没有相比较的索引, WORKER表将被作为查询中的基础表.28.多个平等的索引当SQL语句的执行路径可以使用分布在多个表上的多个索引时, ORACLE会同时使用多个索引并在运行时对它们的记录进行合并, 检索出仅对全部索引有效的记录.在ORACLE选择执行路径时,唯一性索引的等级高于非唯一性索引. 然而这个规则只有当WHERE子句中索引列和常量比较才有效.如果索引列和其他表的索引类相比较. 这种子句在优化器中的等级是非常低的.如果不同表中两个想同等级的索引将被引用, FROM子句中表的顺序将决定哪个会被率先使用. FROM子句中最后的表的索引将有最高的优先级.如果相同表中两个想同等级的索引将被引用, WHERE子句中最先被引用的索引将有最高的优先级.举例:DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.SELECT ENAME,FROM EMPWHERE DEPT_NO = 20AND EMP_CAT = ‘A’;这里,DEPTNO索引将被最先检索,然后同EMP_CAT索引检索出的记录进行合并. 执行路径如下:TABLE ACCESS BY ROWID ON EMPAND-EQUALINDEX RANGE SCAN ON DEPT_IDXINDEX RANGE SCAN ON CAT_IDX29.等式比较和范围比较当WHERE子句中有索引列, ORACLE不能合并它们,ORACLE将用范围比较.举例:DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.SELECT ENAMEFROM EMPWHERE DEPTNO > 20AND EMP_CAT = ‘A’;这里只有EMP_CAT索引被用到,然后所有的记录将逐条与DEPTNO条件进行比较. 执行路径如下:TABLE ACCESS BY ROWID ON EMPINDEX RANGE SCAN ON CAT_IDX30.不明确的索引等级当ORACLE无法判断索引的等级高低差别,优化器将只使用一个索引,它就是在WHERE子句中被列在最前面的.举例:DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引.SELECT ENAMEFROM EMPWHERE DEPTNO > 20AND EMP_CAT > ‘A’;这里, ORACLE只用到了DEPT_NO索引. 执行路径如下:TABLE ACCESS BY ROWID ON EMPINDEX RANGE SCAN ON DEPT_IDX译者按:我们来试一下以下这种情况:SQL> select index_name, uniqueness from user_indexes wheretable_name = 'EMP';INDEX_NAME UNIQUENES------------------------------ ---------EMPNO UNIQUEEMPTYPE NONUNIQUESQL> select * from emp where empno >= 2 and emp_type = 'A' ;no rows selectedExecution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'2 1 INDEX (RANGE SCAN) OF 'EMPTYPE' (NON-UNIQUE)虽然EMPNO是唯一性索引,但是由于它所做的是范围比较, 等级要比非唯一性索引的等式比较低!31.强制索引失效如果两个或以上索引具有相同的等级,你可以强制命令ORACLE优化器使用其中的一个(通过它,检索出的记录数量少) .举例:SELECT ENAMEFROM EMPWHERE EMPNO = 7935AND DEPTNO + 0 = 10 /*DEPTNO上的索引将失效*/AND EMP_TYPE || ‘’ = ‘A’ /*EMP_TYPE上的索引将失效*/这是一种相当直接的提高查询效率的办法. 但是你必须谨慎考虑这种策略,一般来说,只有在你希望单独优化几个SQL时才能采用它.这里有一个例子关于何时采用这种策略,假设在EMP表的EMP_TYPE列上有一个非唯一性的索引而EMP_CLASS上没有索引.SELECT ENAMEFROM EMPWHERE EMP_TYPE = ‘A’AND EMP_CLASS = ‘X’;优化器会注意到EMP_TYPE上的索引并使用它. 这是目前唯一的选择. 如果,一段时间以后, 另一个非唯一性建立在EMP_CLASS上,优化器必须对两个索引进行选择,在通常情况下,优化器将使用两个索引并在他们的结果集合上执行排序及合并. 然而,如果其中一个索引(EMP_TYPE)接近于唯一性而另一个索引(EMP_CLASS)上有几千个重复的值. 排序及合并就会成为一种不必要的负担. 在这种情况下,你希望使优化器屏蔽掉EMP_CLASS索引.用下面的方案就可以解决问题.SELECT ENAMEFROM EMPWHERE EMP_TYPE = ‘A’AND EMP_CLASS||’’= ‘X’;32.避免在索引列上使用计算.WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.举例:低效:SELECT …FROM DEPTWHERE SAL * 12 > 25000;高效:SELECT …FROM DEPTWHERE SAL > 25000/12;译者按:这是一个非常实用的规则,请务必牢记33.自动选择索引如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性.在这种情况下,ORACLE将使用唯一性索引而完全忽略非唯一性索引.举例:SELECT ENAMEFROM EMPWHERE EMPNO = 2326AND DEPTNO = 20 ;这里,只有EMPNO上的索引是唯一性的,所以EMPNO索引将用来检索记录.TABLE ACCESS BY ROWID ON EMPINDEX UNIQUE SCAN ON EMP_NO_IDX34.避免在索引列上使用NOT通常,我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.举例:低效: (这里,不使用索引)SELECT …FROM DEPTWHERE DEPT_CODE NOT = 0;高效: (这里,使用了索引)SELECT …FROM DEPTWHERE DEPT_CODE > 0;需要注意的是,在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符.NOT > to <=NOT >= to <NOT < to >=NOT <= to >译者按:在这个例子中,作者犯了一些错误. 例子中的低效率SQL是不能被执行的. 我做了一些测试:SQL> select * from emp where NOT empno > 1;no rows selectedExecution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)SQL> select * from emp where empno <= 1;no rows selectedExecution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)两者的效率完全一样,也许这符合作者关于” 在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符” 的观点.35.用>=替代>如果DEPTNO上有一个索引,高效:SELECT *FROM EMPWHERE DEPTNO >=4低效:SELECT *FROM EMPWHERE DEPTNO >3两者的区别在于,前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录. 36.用UNION替换OR (适用于索引列)通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.在下面的例子中, LOC_ID 和REGION上都建有索引.高效:SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10UNIONSELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE REGION = “MELBOURNE”低效:SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10 O R REGION = “MELBOURNE”如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.注意:WHERE KEY1 = 10 (返回最少记录)OR KEY2 = 20 (返回最多记录)ORACLE 内部将以上转换为WHERE KEY1 = 10 AND((NOT KEY1 = 10) AND KEY2 = 20)37.用IN来替换OR下面的查询可以被更有效率的语句替换:低效:SELECT….FROM LOCATIONWHERE LOC_ID = 10OR LOC_ID = 20OR LOC_ID = 30高效SELECT…FROM LOCATIONWHERE LOC_IN IN (10,20,30);译者按:这是一条简单易记的规则,但是实际的执行效果还须检验,在ORACLE8i下,两者的执行路径似乎是相同的.38.避免在索引列上使用IS NULL和IS NOT NULL避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引.对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.举例:如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B 值为(123,null) , ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000条具有相同键值的记录,当然它们都是空!因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.举例:低效: (索引失效)SELECT …FROM DEPARTMENTWHERE DEPT_CODE IS NOT NULL;高效: (索引有效)SELECT …FROM DEPARTMENTWHERE DEPT_CODE >=0;39.总是使用索引的第一个列如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引.译者按:这也是一条简单而重要的规则. 见以下实例.SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));Table created.SQL> create index multindex on multiindexusage(inda,indb);Index created.SQL> set autotrace traceonlySQL> select * from multiindexusage where inda = 1;Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE'2 1 INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE)SQL> select * from multiindexusage where indb = 1;Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE'很明显, 当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引。

关于SQL文优化问题总结

关于SQL文优化问题总结

关于SQL文优化问题总结【摘要】实际系统中遇到性能问题是非常常见的,性能优化有许多方面,其中包括硬件方面,软件方面,包括服务器端,客户端等等。

本文重点基于oracle分析了影响sql文性能的原因,然后列举了几点性能优化的对策,希望给开发人员在编码时提供帮助,给sql的性能问题调查者提供一个方向。

【关键词】oracle;性能问题;sql文优化一、问题提出之前有个项目,其中的批处理定期调用一个存储过程,在测试环境中运行没有问题,但是正式运行出现了错误,执行存储过程时出现了错误:提示是表空间不足。

为了解决这个问题,笔者对sql 文的性能优化进行了学习和研究。

二、问题调查与解决由于该存储过程内容比较多,大概有3000多行,也不能判断那部分出了问题,首先在可能出现问题的地方追加了log信息。

由于测试环境中该问题不能再现,所以代码更新到了实际环境中进行运行,通过log发现是在执行某个sql文时出的错误,这个sql文涉及到了10多个表,而其中表中的数据量比较大。

执行时用到的临时表空间高达40g,后来通过调查对sql的进行了调整,只是修改了where条件中其中两个条件的顺序,这个问题就解决了。

三、sql文性能原因分析(1)在大记录集上进行高成本操作,如使用了引起排序的谓词等。

(2)过多的i/o操作(含物理i/o与逻辑i/o),最典型的就是未建立恰当的索引,导致对查询表进行全表扫描。

减少访问数据库的次数,就能实际上减少oracle的工作量。

(3)处理了太多的无用记录,如在多表连接时过滤条件位置不当导致中间结果集包含了太多的无用记录。

(4)未充分利用数据库提供的功能,如查询的并行化处理等。

四、sql文性能优化总结(1)建立恰当的索引。

对经常进行排序和连接操作的字段建立索引。

(2)避免使用”*”,sql文中引用”*”,使用起来的确非常方便,但是效率非常低,主要是oracle在解析的过程中,会将”*”一次转化成所有的列名,这个工作是通过查询数据字典完成的。

优化SQL对ORACLE数据库性能的提高

优化SQL对ORACLE数据库性能的提高

3科技资讯科技资讯S I N &T NOLOGY I NFO RM TI ON 2008NO .28SC I EN CE &TECH NO LOG Y I N FOR M A TI O N 信息技术大多数情况下,系统运行缓慢不是由于所有部件都饱和引起的,而是由于系统中的某个部分限制了整体的性能,这部分称为瓶颈。

通常影响ORA CL E 数据库性能指标的三个瓶颈主要是:CP U 、内存、I /O 。

数据库性能的优化主要是or a c l e 数据库参数的调整、磁盘I /O 调整、应用程序S QL语句分析及设计、网络性能调整等。

本文主要通过优化S QL 语句来提高ORACL E 数据库的性能。

1SQ L 语句处理流程如图1所示。

1.1打开游标从上图可以看出处理S QL 语句的第一步就是要打开一个游标,事实上,一个完整的S QL 处理过程就是一个游标的生命周期。

1.2共享SQLOr a cl e 内存中有一个区叫SHA R ED _PO OL ,这个区的主要作用就是将S Q L 语句存放在这个区内,当客户发出一个新的S QL 语句,数据库引擎首先会到这个区查找是否有相同的S QL ,如果有,则避免了解析、分析索引、制定执行计划等一系列的动作。

如果没有则需要进行ha r d pa r s e 。

1.3绑定变量如果在S QL 中指定了绑定变量,需要在这个阶段给S QL 附上绑定变量的值。

1.4并行处理如果S Q L 需要进行并行处理,在这一阶段需要把整个S Q L 分割成多个并行的部分。

1.5执行查询Or a c l e 按照执行计划指定的方式执行SQL,执行UPDATE 和DE LE TE 语句时,必须将行锁定,以免其他用户修改。

Or a cl e 先从数据库缓冲区中寻找是否存在所要的数据块,如果存在,就直接读或修改,否则从物理文件中读到数据库缓冲区中。

1.6返回结果对S EL ECT 语句需要返回结果的语句,首先看是否需要排序,需要,则排序后返回给用户,然后根据内存的大小不同,可以一次取出一行数据,也可以一次取一组数据。

确保Oracle数据库sql语句高效执行的优化总结(二)

确保Oracle数据库sql语句高效执行的优化总结(二)

【接确保Oracle数据库sql语句高效执行的优化总结(一)】2.4 10053和10046事件2.4.1 10053事件我们在查看一条SQL的执行计划的时候,只能看到CBO 最终告诉我们的执行计划结果,但是不知道CBO 是根据什么来做的。

如果遇到了执行计划失真,如:一个SQL语句,很明显oracle应该使用索引,但是执行计划却没有使用索引。

无法进行分析判断。

10053事件就提供了这样的功能。

它产生的trace文件提供了Oracle如何选择执行计划,为什么会得到这样的执行计划信息。

对于10053事件的trace文件,我们只能直接阅读原始的trace文件,不能使用tkprof工具来处理,tkprof工具只能用来处理sql_trace 和10046事件产生的trace文件。

10053事件有两个级别:Level2:2级是1级的一个子集,它包含以下内容:Column statisticsSingle Access PathsJoin CostsTable Joins ConsideredJoin Methods Considered (NL/MS/HA)Level1:1级比2级更详细,它包含2级的所有内容,在加如下内容:Parameters used by the optimizerIndex statistics启用10053事件:关闭10053事件:说明:(1)sqlplus中打开autotrace看到的执行计划实际上是用explain plan 命令得到的,explain plan 命令不会进行bind peeking。

应该通过v$sql_plan查看SQL的真实的执行计划。

(2)10053只对CBO有效,而且如果一个sql语句已经解析过,就不会产生新的trace信息。

2.4.2 10046事件10046 事件主要用来跟踪SQL语句,它并不是ORACLE 官方提供给用户的命令,在官方文档上也找不到事件的说明信息。

浅谈Oracle数据库SQL性能优化

浅谈Oracle数据库SQL性能优化

浅谈Oracle数据库SQL性能优化摘要:随着计算机信息网络技术的不断发展,数据库系统取得很大突破。

面临网络化时代的进步,人们对网络信息的需求的也变得逐渐走向多元化。

网络信息数据库存取技术逐渐被广泛运用,数据库系统规模也越来越大。

目前Oracle 就是被广泛应用的一种数据库,其信息存储量能满足人们日益增长的需求,但为了能够保证其能够流畅稳定安全地运行,应当对其进行一定的优化措施。

关键词:Oracle数据库;SQL优化随着数据库技术功能逐步增加,应用范围逐渐扩展,效果也是日渐明显。

随着网络信息吞吐量的逐步增加,数据库系统在对数据进行处理时算法变得十分繁琐。

数据库系统如果长时间的超负荷工作就会变得反应迟钝影响效率,甚至可能导致死锁。

由于天天都将会有大量的SQL语句访问Oracl数据库系统,系统需要很多时间来处理这些访问,而SQL语句直接影响到Oracl数据库系统性能,所以运用对SQL语句优化的方法来提升ORACLE数据库的性能显得十分必要。

1、对SQL进行优化的必要性数据库系统作为数据管理的主要组成部分主要作用是存储供相关人员查阅大量信息,实现网络资源共享。

查询操作在数据库系统的各种操作中居于首位,直接关系到数据库系统的运行状态。

假如数据查询操作量过大,会给系统带来很大的负担,系统反应速度变慢,严重者可能就会引起系统瘫痪。

因此,为了保证数据库系统的高效正常运行,必须对SQL语句进行优化[1]。

图1.1SQL语句优化2、SQL优化的目标往往由于SQL的结构设计的问题,很可能使得正常运行的一个数据库系统出现性能问题。

所以必须对SQL语句进行必要的调整,达到有效提升数据库系统性能的目的。

对SQL结构的优化本质就是简化繁琐的数据结构,常规方法一般就是对SQL语法进行一些调整,基本方法是把程序中繁琐的SQL语句结构简化,保持服务器的搜索数据能力处于最佳运行状态,有效降低程序中表扫描的时间,促使所以功能得以充分发挥,尽量使服务器的处理器时间和输入输出时间保持平衡。

Oracle数据库性能优化与案例分析

Oracle数据库性能优化与案例分析
技术创新,变革未来
Oracle数据库性能优化与案例分析
性能优化探讨
• 原因:为什么? • 慢(响应时间) • 慢(吞吐量)
性能优化探讨
• 目的:为了什么? • 快(响应时间) • 快(吞吐量)
性能优化之案例分析
• 案例之方法论 • 案例之登录访问 • 案例之资源 • 案例之锁
性能优化方法论发展
• 登录输入指标测量 • Logons:= EndSnap. logons cumulative– StartSnap. logons
cumulative。 • Logons Per Second:= Logons / TimeInterval
案例之登录访问
登录输出指标测量:
Logon Response Time:= Network Response Time * 10 + Native TCP Logon :=Network Response Time * 10 + Listener Response Time + Native IPC Logon Time 。
案例之登录访问
• 例:

某医院HIS业务系统的账户登录操作异常缓慢,部分情况下
甚至会出现长时间的卡壳情况,业务影响主要发生在每天早上
的上班时刻。
案例之登录访问
优化过程: • 账户登录过程一般涉及到在账户表格以及对应日志表格上的冲
突,比如Buffer busy waits或者TX lock。AWR未体现该特征。 • AWR报告显示connection management call elapsed time时间偏长
成功率:98% 高 失败率:2% 低
失败人数:500*2%=10

oracle sql优化常用的15种方法

oracle sql优化常用的15种方法

oracle sql优化常用的15种方法1. 使用合适的索引索引是提高查询性能的重要手段。

在设计表结构时,根据查询需求和数据特点合理地添加索引。

可以通过创建单列索引、复合索引或者位图索引等方式来优化SQL查询。

2. 确保SQL语句逻辑正确SQL语句的逻辑错误可能会导致低效查询。

因此,在编写SQL语句前,需要仔细分析查询条件,确保逻辑正确性。

3. 使用连接替代子查询在一些场景下,使用连接(JOIN)操作可以替代子查询,从而减少查询的复杂度。

连接操作能够将多个数据集合合并为一个结果集,避免多次查询和表的扫描操作。

4. 避免使用通配符查询通配符查询(如LIKE '%value%')在一些情况下可能导致全表扫描,性能低下。

尽量使用前缀匹配(LIKE 'value%')或者使用全文索引进行模糊查询。

5. 注意选择合适的数据类型选择合适的数据类型有助于提高SQL查询的效率。

对于整型数据,尽量使用小范围的数据类型,如TINYINT、SMALLINT等。

对于字符串数据,使用CHAR字段而不是VARCHAR,可以避免存储长度不一致带来的性能问题。

6. 优化查询计划查询计划是数据库在执行SQL查询时生成的执行计划。

通过使用EXPLAIN PLAN命令或者查询计划工具,可以分析查询计划,找出性能瓶颈所在,并对其进行优化。

7. 减少磁盘IO磁盘IO是影响查询性能的重要因素之一。

可以通过增加内存缓存区(如SGA)、使用高速磁盘(如SSD)、使用合适的文件系统(如ASM)等方式来减少磁盘IO。

8. 分区表对于大数据量的表,可以考虑使用分区表进行查询优化。

分区表可以将数据按照某个规则分散到不同的存储区域,从而减少查询范围和加速查询。

9. 批量操作尽量使用批量操作而不是逐条操作,可以减少数据库的事务处理开销,提高SQL执行效率。

可以使用INSERT INTO SELECT、UPDATE、DELETE等批量操作语句来实现。

oracle性能优化总结

oracle性能优化总结

Oracle 性能优化50个方法1. 选用适合的ORACLE优化器ORACLE的优化器共有3种: a. RULE (基于规则) b. COST (基于成本) c. CHOOSE (选择性)设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖. 为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze 命令,以增加数据库中的对象统计信息(object statistics)的准确性. 如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器. 在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器.2. 访问Table的方式ORACLE 采用两种访问表中记录的方式:a. 全表扫描全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描,这样的访问方式是效率最低的.b. 通过ROWID访问表你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.3. 共享SQL语句为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用. 可惜的是ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询. 数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,当然被共享的可能性也就越大了. 当你向ORACLE 提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句. 这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同(包括空格,换行等). 共享的语句必须满足三个条件:A. 字符级的比较: 当前被执行的语句和共享池中的语句必须完全相同. 例如:SELECT * FROM EMP;和下列每一个都不同SELECT * from EMP;Select * From Emp;SELECT * FROM EMP;B. 两个语句所指的对象必须完全相同: 例如:用户对象名如何访问Jack sal_limit private synonymWork_city public synonymPlant_detail public synonymJill sal_limit private synonymWork_city public synonymPlant_detail table owner考虑一下下列SQL语句能否在这两个用户之间共享.C. 两个SQL语句中必须使用相同的名字的绑定变量(bind variables) 例如:第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值)select pin , name from people where pin = :blk1.pin;select pin , name from people where pin = :blk1.pin;select pin , name from people where pin = :blk1.ot_ind;select pin , name from people where pin = :blk1.ov_ind;4. 选择基础表所谓基础表是被最先被访问的表,通常是以全表扫描的方式被访问,由于优化器不同,SQL语句的基础表的选择也不同.1.COST优化器会检查SQL中每个表的物理大小,索引状态,然后选择花费最底的执行路径.他会自己选择基础表2.RULE优化器,在所有连接条件都有索引对应的前提下,选择FROM子句中最后那个表作为基础表.ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并. 例如: 表TAB1 16,384 条记录表TAB2 1 条记录。

第09章Oracle的性能优化

第09章Oracle的性能优化

9.2 SQL语句的优化
9.2.1 SQL语句的优化规则 9.2.2 SQL语句优化的具体方法
9.2.1 SQL语句的优化规则
(1)去掉不必要的大表、全表扫描。不必要的大表、全表 扫描会造成不必要的输入输出,而且还会拖垮整个数据库;
(2)检查优化索引的使用 这对于提高查询速度来说非常重 要;
(3)检查子查询,考虑SQL子查询是否可以用简单连接的 方式进行重新书写;
系统的服务器,可以使用sar –u命令查看CPU的使用率;NT 操作系统的服务器,可以使用NT的性能管理器来查看CPU 的使用率。
出现CPU资源不足的情况是很多的:SQL语句的重解析、 低效率的SQL语句、锁冲突都会引起CPU资源不足。
2.查看SQL语句的解析情况 (1)数据库管理员可以执行下述语句来查看SQL语句的解析 情况:
9.3 Oracle运行环境的优化
9.3.1 内存结构的调整 9.3.2 物理I/O的调整 9.3.3 CPU的优化调整 9.3.4 网络配置的优化 9.3.5 Oracle碎片整理 9.3.6 Oracle系统参数的调整
9.3.1 内存结构的调整
内存参数的调整主要是指Oracle数据库的系统全局区 (SGA)的调整。SGA主要由三部分构成:共享池、数 据缓冲区、日志缓冲区。
2.数据缓冲区 数据库管理员可以通过下述语句,来查看数据库数据缓冲区
的使用情况。
SELECT name, FROM v$sysstat WHERE name IN ('db block gets','consistent gets','physical reads');
根据查询出来的结果可以计算出数据缓冲区的使用命中率:

Oracle中优化SQL的原则

Oracle中优化SQL的原则

Oracle中优化SQL的原则1.已经检验的语句和已在共享池中的语句之间要完全一样2.变量名称尽量一致3.合理使用外联接4.少用多层嵌套5.多用并发语句的优化步骤一般有:1.调整sga区,使得sga区的是用最优.2.sql语句本身的优化,工具有explain,sql trace等3.数据库结构调整4.项目结构调整写语句的经验:1.对于大表的查询使用索引2、少用in,exist等3、使用集合运算1.对于大表查询中的列应尽量避免进行诸如To_char,to_date,to_number等转换2.有索引的尽量用索引,有用到索引的条件写在前面如有可能和有必要就建立一些索引.3.尽量避免进行全表扫描,限制条件尽可能多,以便更快搜索到要查询的数据如何让你的SQL运行得更快不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句.在对它们进行适当的优化后,其运行速度有了明显地提高!下面我将从这三个方面分别进行总结:为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(1秒).一、不合理的索引设计例:表record有620000行,试看在不同的索引下,下面几个SQL的运行情况:1.在date上建有一非个群集索引select count(*) from record where date>'19991201'and date < '19991214' and amoun > 2000 --------- (25秒)select date,sum(amount) from record group by date --------- (55秒)select count(*) from record where date>'19990901' and place in ('BJ','SH') --------- (27秒)分析:date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行.2.在date上的一个群集索引select count(*) from record where date > '19991201'and date < '19991214' and amount > 2000 ---------(14秒)select date,sum(amount) from record group by date ---------(28秒)select count(*) from record where date > '19990901' and place in ('BJ','SH') ---------(14秒)分析:在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度.3.在place,date,amount上的组合索引select count(*) from record where date > '19991201' and date < '19991214' and amount > 2000 –(26秒) select date,sum(amount) from record group by date---------(27秒)select count(*) from record where date > '19990901' and place in ('BJ, 'SH') --------- (1秒)分析:这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的.4.在date,place,amount上的组合索引select count(*) from record where date > '19991201' and date <'19991214' and amount>2000----( 1秒) select date,sum(amount) from record group by date --------- (11秒)select count(*) from record where date>'19990901' and place in ('BJ','SH') --------- (1秒)分析:这是一个合理的组合索引.它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优.5.总结:缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上.一般来说:①.有大量重复值、且经常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,可考虑建立群集索引;②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列.二、不充份的连接条件:例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在account_no 上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:select sum(a.amount) from account a,card b where a.card_no = b.card_no-------- (20秒)将SQL改为:select sum(a.amount) from account a,card b where a.card_no = b.card_no and a.account_no=b.account_no-------- ( 1秒)分析:在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O可见,只有充份的连接条件,真正的最佳方案才会被执行.总结:1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案.连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案.2.查看执行方案的方法用set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302).三、不可优化的where子句1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:select * from record wheresubstring(card_no,1,4)='5378'-------- (13秒)select * from record where amount/30 < 1000-------- (11秒)select * from record where convert(char(10),date,112)='19991201'-------- (10秒)分析:where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL 优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:select * from record where card_no like '5378%'-------- (1秒)select * from record where amount < 1000*30--------(11秒)select * from record where date= '1999/12/01'-------- ( 1秒)你会发现SQL明显快起来!2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:select count(*) from stuff where id_no in('0','1') -------- (23秒)分析:where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1')转化为id_no ='0' or id_no='1'来执行.我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上(根据showplan),它却采用了&quot;OR策略&quot;,即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果.因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响.实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间竟达到220秒!还不如将or子句分开:select count(*) from stuff where id_no='0'select count(*) from stuff where id_no='1'得到两个结果,再作一次加法合算.因为每句都使用了索引,执行时间只有3秒,在620000行下,时间也只有4秒.或者,用更好的方法,写一个简单的存储过程:create proc count_stuff asdeclare @a intdeclare @b intdeclare @c intdeclare @d char(10)beginselect @a=count(*) from stuff where id_no='0'select @b=count(*) from stuff where id_no='1'endselect @c=@a+@bselect @d=convert(char(10),@c)print @d直接算出结果,执行时间同上面一样快!总结:可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销.1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边.2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引.3.要善于使用存储过程,它使SQL变得更加灵活和高效.从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生.其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计.。

ORACLE常用SQL优化hint语句

ORACLE常用SQL优化hint语句

ORACLE常⽤SQL优化hint语句在SQL语句优化过程中,我们经常会⽤到hint,现总结⼀下在SQL优化过程中常见Oracle HINT的⽤法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化⽅法,并获得最佳吞吐量,使资源消耗最⼩化. 例如: SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’; 2. /*+FIRST_ROWS*/ 表明对语句块选择基于开销的优化⽅法,并获得最佳响应时间,使资源消耗最⼩化. 例如: SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’; 3. /*+CHOOSE*/ 表明如果数据字典中有访问表的统计信息,将基于开销的优化⽅法,并获得最佳的吞吐量; 表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化⽅法; 例如: SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’; 4. /*+RULE*/ 表明对语句块选择基于规则的优化⽅法. 例如: SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’; 5. /*+FULL(TABLE)*/ 表明对表选择全局扫描的⽅法. 例如: SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO=’SCOTT’; 6. /*+ROWID(TABLE)*/ 提⽰明确表明对指定表根据ROWID进⾏访问. 例如: SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>=’AAAAAAAAAAAAAA’ AND EMP_NO=’SCOTT’; 7. /*+CLUSTER(TABLE)*/ 提⽰明确表明对指定表选择簇扫描的访问⽅法,它只对簇对象有效. 例如: SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS WHERE DPT_NO=’TEC304′ AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO; 8. /*+INDEX(TABLE INDEX_NAME)*/ 表明对表选择索引的扫描⽅法. 例如: SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX=’M'; 9. /*+INDEX_ASC(TABLE INDEX_NAME)*/ 表明对表选择索引升序的扫描⽅法. 例如: SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO=’SCOTT’; 10. /*+INDEX_COMBINE*/ 为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合⽅式. 例如: SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS WHERE SAL<5000000 AND HIREDATE 11. /*+INDEX_JOIN(TABLE INDEX_NAME)*/ 提⽰明确命令优化器使⽤索引作为访问路径. 例如: SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE FROM BSEMPMS WHERE SAL<60000; 12. /*+INDEX_DESC(TABLE INDEX_NAME)*/ 表明对表选择索引降序的扫描⽅法. 例如: SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT'; 13. /*+INDEX_FFS(TABLE INDEX_NAME)*/ 对指定的表执⾏快速全索引扫描,⽽不是全表扫描的办法. 例如: SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305'; 14. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/ 提⽰明确进⾏执⾏规划的选择,将⼏个单列索引的扫描合起来. 例如: SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='SCOTT' AND DPT_NO='TDC306'; 15. /*+USE_CONCAT*/ 对查询中的WHERE后⾯的OR条件进⾏转换为UNION ALL的组合查询. 例如: SELECT /*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M'; 16. /*+NO_EXPAND*/ 对于WHERE后⾯的OR 或者IN-LIST的查询语句,NO_EXPAND将阻⽌其基于优化器对其进⾏扩展. 例如: SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M'; 17. /*+NOWRITE*/ 禁⽌对查询块的查询重写操作. 18. /*+REWRITE*/ 可以将视图作为参数. 能够对视图的各个查询进⾏相应的合并. 例如: SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO ,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL; 20. /*+NO_MERGE(TABLE)*/ 对于有可合并的视图不再合并. 例如: SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELECT DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL; 21. /*+ORDERED*/ 根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接. 例如: SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C WHERE A.COL1=B.COL1 ANDB.COL1=C.COL1; 22. /*+USE_NL(TABLE)*/ 将指定表与嵌套的连接的⾏源进⾏连接,并把指定表作为内部表. 例如: SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO; 23. /*+USE_MERGE(TABLE)*/ 将指定的表与其他⾏源通过合并排序连接⽅式连接起来. 例如: SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHEREBSEMPMS.DPT_NO=BSDPTMS.DPT_NO; 24. /*+USE_HASH(TABLE)*/ 将指定的表与其他⾏源通过哈希连接⽅式连接起来. 例如: SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHEREBSEMPMS.DPT_NO=BSDPTMS.DPT_NO; 25. /*+DRIVING_SITE(TABLE)*/ 强制与ORACLE所选择的位置不同的表进⾏查询执⾏. 例如: SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO; 26. /*+LEADING(TABLE)*/ 将指定的表作为连接次序中的⾸表. 27. /*+CACHE(TABLE)*/ 当进⾏全表扫描时,CACHE提⽰能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使⽤端 例如: SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS; 当进⾏全表扫描时,CACHE提⽰能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使⽤端 例如: SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS; 29. /*+APPEND*/ 直接插⼊到表的最后,可以提⾼速度. insert /*+append*/ into test1 select * from test4 ; 30. /*+NOAPPEND*/ 通过在插⼊语句⽣存期内停⽌并⾏模式来启动常规插⼊. insert /*+noappend*/ into test1 select * from test4 ;----------------------------------------------------------------------------Optimization Approaches Access MethodsALL_ROWS AND_EQUALCHOOSE CLUSTERFIRST RULES FULLRULE HASHParallel Execution HASH_AJAPPEND*ORDERED HASH_SJ ***STAR**INDEXSTAR_TRANSFORMATION*INDEX_ASCJoin Operations INDEX_COMBINE*DRIVING_SITE*INDEX_DESCUSE_HASH**INDEX_FFS*USE_MERGE MERGE_AJ**USE_NL MERGE_SJ***Additional Hints ROW_IDCACHE USE_CONCATNOCACHE NO_EXPAND***PUSH_SUBQ REWRITE***MERGE***NOREWRITE***NO_MERGE*Join OrdersPUSH_JOIN_PRED***NO_PUSH_JOIN_PRED***NOAPPEND*ORDERED PREDICATES***NOPARALLELPARALLELPARALLEL_INDEX*NO_PARALLEL_INDEX*** 提⽰(hint)从Oracle7中引⼊,⽬的是弥补基于成本优化器的缺陷。

Oracle之SQL语句性能优化(34条优化方法)

Oracle之SQL语句性能优化(34条优化方法)

Oracle之SQL语句性能优化(34条优化⽅法)好多同学对sql的优化好像是知道的甚少,最近总结了以下34条仅供参考。

(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⽐较了。

SQL数据库怎么进行优化_SQL数据库有什么优化方式

SQL数据库怎么进行优化_SQL数据库有什么优化方式

SQL数据库怎么进行优化_SQL数据库有什么优化方式优化SQLServer数据库的一些经验和注意事项,详细介绍了SQL 语句优化的基本原则,包括索引、查询和游标的使用等。

下面由店铺为大家整理的SQL数据库优化方式,希望大家喜欢!SQL数据库优化的方式1. 利用表分区分区将数据在物理上分隔开,不同分区的数据可以制定保存在处于不同磁盘上的数据文件里。

这样,当对这个表进行查询时,只需要在表分区中进行扫描,而不必进行全表扫描,明显缩短了查询时间,另外处于不同磁盘的分区也将对这个表的数据传输分散在不同的磁盘I/O,一个精心设置的分区可以将数据传输对磁盘I/O竞争均匀地分散开。

对数据量大的时时表可采取此方法。

可按月自动建表分区。

2. 别名的使用别名是大型数据库的应用技巧,就是表名、列名在查询中以一个字母为别名,查询速度要比建连接表快1.5倍。

3. 索引Index的优化设计索引可以大大加快数据库的查询速度。

但是并不是所有的表都需要建立索引,只针对大数据量的表建立索引就好。

缺点:1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。

3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

索引需要维护:为了维护系统性能,索引在创建之后,由于频繁地对数据进行增加、删除、修改等操作使得索引页发生碎块,因此,必须对索引进行维护。

4. 物化视图(索引视图)一般的视图是虚拟的,而物化视图是实实在在的数据区域,是要占据存储空间的,另外系统刷新物化视图也需要耗费一定的资源,但是它却换来了效率和灵活性。

索引视图更适合在OLAP(读取较多,更新较少)的数据库中使用,不适合在OLTP(记录即时的增、删、改、查)的数据库中使用。

物化视图的注意事项:1.对于复杂而高消耗的查询,如果使用频繁,应建成物化视图。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

(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) = ( SELECTTAB_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 DEP T.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(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 SELECTACCT_NUM, BALANCE_AMT FROM DEBIT_TRANSACTIONS WHERE TRAN_DATE = '31-DEC-95'高效: SELECT ACCT_NUM, BALANCE_AMT FROM DEBIT_TRANSACTIONSWHERE 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 NULLDEPT_DESC NOT NULLDEPT_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 EMPWHERE JOB = ‘PRESIDENT'OR JOB = ‘MANAGER' GROUP JOB。

相关文档
最新文档