转自:
https://www.ibm.com/developerworks/mydeveloperworks/wikis/home/wiki/oracle/page/oracle%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96?lang=en
(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) =( 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
今天同事碰到一个SQL的性能问题,主要是MERGE INTO的性能问题,执行脚本的时候,居然耗时50多分钟,汗!简直让人抓狂,脚本如下:
MERGE INTO EDS.TW_DP_B_TDTERM_IMEI_DAY DM
USING T_IMEI_DAY_1111 TEMP
ON(
DM.DATE_CD = TEMP.DATE_CD AND
DM.CITY_ID = TEMP.CITY_ID AND
DM.IMEI = TEMP.IMEI AND
DM.USR_NBR = TEMP.USR_NBR
)
WHEN MATCHED THEN UPDATE SET
DM.GSM_FLUX = TEMP.GSM_FLUX ,
DM.TD_FLUX = TEMP.TD_FLUX ,
DM.GPRS_FLUX = TEMP.GPRS_FLUX
WHEN NOT MATCHED THEN INSERT(
DM.DATE_CD ,
DM.CITY_ID ,
DM.IMEI ,
DM.BUSS_CITY_ID ,
DM.TYPE_ID ,
DM.USR_NBR ,
DM.GSM_FLUX ,
DM.TD_FLUX ,
DM.GPRS_FLUX
)
VALUES(
TEMP.DATE_CD ,
序列介绍
序列是一个计数器,它并不会与特定的表关联。通过创建Oracle序列和触发器实现表的主键自增。 序列的用途一般用来填充主键和计数。
序列使用
1.创建序列
ORACLE序列的语法格式为:
CREATE SEQUENCE 序列名
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE/ MINVALUE n|NOMAXVALUE}]
[{CYCLE|NOCYCLE}]
[{CACHE n|NOCACHE}];
1)INCREMENT BY用于定义序列的步长,如果省略,则默认为1,如果出现负值,则代表Oracle序列的值是按照此步长递减的。
2)START WITH 定义序列的初始值(即产生的第一个值),默认为1。
3)MAXVALUE 定义序列生成器能产生的最大值。选项NOMAXVALUE是默认选项,代表没有最大值定义,这时对于递增Oracle序列,系统能够产生的最大值是10的27次方;对于递减序列,最大值是-1。
4)MINVALUE定义序列生成器能产生的最小值。选项NOMAXVALUE是默认选项,代表没有最小值定义,这时对于递减序列,系统能够产生的最小值是?10的26次方;对于递增序列,最小值是1。
5)CYCLE和NOCYCLE 表示当序列生成器的值达到限制值后是否循环。CYCLE代表循环,NOCYCLE代表不循环。如果循环,则当递增序列达到最大值时,循环到最小值;最小值为1。对于递减序列达到最小值时,循环到最大值。如果不循环,达到限制值后,继续产生新值就会发生错误。
ORACLE OCP考试有道题关于序列,如下所示
Evaluate the following CREATE SEQUENCE statement:
CREATE SEQUENCE seq1
START WITH 100
INCREMENT BY 10
MAXVALUE 200
CYCLE
NOCACHE;
The sequence SEQ1 has generated numbers up to the maximum limit of 200. You issue the following
SQL statement:
SELECT seq1.nextval FROM dual;
What is displayed by the SELECT statement?
A. 1
B. 10
C. 100
D. an error
答案:A
6)CACHE(缓冲)定义存放序列的内存块的大小,默认为20。NOCACHE表示不对序列进行内存缓冲。对序列进行内存缓冲,可以改善序列的性能。 缓存选项会造成数据丢失,当实例异常关闭时。
2.删除序列
语法是DROP SEQUENCE [schema].序列名;
CREATE SEQUENCE SEQ_TEST
INCREMENT BY 1
START WITH 1
MINVALUE 1 NOMAXVALUE
NOCYCLE;
DROP SEQUENCE SEQ_TEST;
3:序列使用
CURRVAL:返回序列的当前值。
NEXTVAL:序列递增,返回下一值。
你不能使用序列的CURRVAL和NEXTVAL,在下面情况下(具体参见官方文档):
1:在DELETE、SELECT、UPDATE的子查询中
2:在视图或物化事物的查询中。
3:SELECT查询中使用了DISTINCT操作符。
4:SELECT查询中有GROUP BY或ORDER BY
4:序列查看
SELECT * FROM USER_SEQUENCES;
SELECT * FROM ALL_SEQUENCES;
SELECT * FROM DBA_SEQUENCES;
5:序列修改
不能修改序列的初始值,否则会报ORA-02283:
SQL> ALTER SEQUENCE SEQ_TEST START WITH 2;
ALTER SEQUENCE SEQ_TEST START WITH 2
ORA-02283: 无法更改启动序列号
SQL> ALTER SEQUENCE SEQ_TEST INCREMENT BY 2;
Sequence altered
本文链接