分类: Oracle
2008-09-11 10:37:02
我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习、摘录、并汇总部分资料与大家分享! (1)选择最有效率的表名顺序(只在基于规则的优化器中有效): orACLE
的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving
table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询,
那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2)Where子句中的连接顺序.: orACLE采用自下而上的顺序解析Where子句,根据这个原理,表之间的连接必须写在其他Where条件之前, 那些可以过滤掉最大数量记录的条件必须写在Where子句的末尾. (3)Select子句中避免使用 ‘ * ‘: (4)减少访问数据库的次数: (5)在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200 (6)使用DECODE函数来减少处理时间: (7)整合简单,无关联的数据库访问: (8)删除重复记录: Delete FROM EMP E Where E.ROWID > (Select MIN(X.ROWID) FROM EMP X Where X.EMP_NO = E.EMP_NO); (9)用TRUNCATE替代Delete: (10) 尽量多使用COMMIT: COMMIT所释放的资源: a. 回滚段上用于恢复数据的信息. b. 被程序语句获得的锁 c. redo log buffer 中的空间 d. orACLE为管理上述3种资源中的内部花费 (11) 用Where子句替换HAVING子句: (12) 减少对表的查询: Select TAB_NAME FROM TABLES Where (TAB_NAME,DB_VER) = ( Select TAB_NAME,DB_VER FROM TAB_COLUMNS Where VERSION = 604) (13) 通过内部函数提高SQL效率.: (14) 使用表的别名(Alias): (15) 用EXISTS替代IN、用NOT EXISTS替代NOT IN: 例子: (高效)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语句: 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) 用索引提高效率: Alter INDEX <INDEXNAME> REBUILD (18) 用EXISTS替换DISTINCT: (低效): 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 通常, (22) 避免在索引列上使用计算. 举例: 低效: 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 两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录. (24) 用UNION替换OR (适用于索引列) 高效: 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 低效: 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 低效: (索引失效) Select … FROM DEPARTMENT Where DEPT_CODE IS NOT NULL; 高效: (索引有效) Select … FROM DEPARTMENT Where DEPT_CODE >=0; (27) 总是使用索引的第一个列: (28) 用UNION-ALL 替换UNION ( 如果有可能的话): 低效: Select ACCT_NUM, BALANCE_AMT FROM DEBIT_TRANSACTIONS Where TRAN_DATE = '31-DEC-95' UNION Select ACCT_NUM, BALANCE_AMT FROM DEBIT_TRANSACTIONS Where TRAN_DATE = '31-DEC-95' 高效: Select ACCT_NUM, BALANCE_AMT FROM DEBIT_TRANSACTIONS Where 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中所有的列必须定义为非空. Where子句使用的索引和ORDER BY子句中所使用的索引不能并列. 例如: 表DEPT包含以下列: DEPT_CODE PK NOT NULL DEPT_DESC NOT NULL DEPT_TYPE NULL 低效: (索引不被使用) Select DEPT_CODE FROM DEPT orDER BY DEPT_TYPE 高效: (使用索引) Select DEPT_CODE FROM DEPT Where DEPT_TYPE > 0 (30) 避免改变索引列的类型.: 假设 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子句: 在 下面的例子里, (1)‘!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中. (2) ‘||'是字符连接函数. 就象其他函数那样, 停用了索引. (3) ‘+'是数学函数. 就象其他数学函数那样, 停用了索引. (4)相同的索引列不能互相比较,这将会启用全表扫描. (32) a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高. (33) 避免使用耗费资源的操作: 带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL语句会启动SQL引擎 执 行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序. 通常, 带有UNION, MINUS , INTERSECT的SQL语句都可以用其他方式重写. 如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是可以考虑的, 毕竟它们的可读性很强 (34) 优化GROUP BY: 低效: Select JOB , AVG(SAL) FROM EMP GROUP JOB HAVING JOB = ‘PRESIDENT' or JOB = ‘MANAGER' 高效: Select JOB , AVG(SAL) FROM EMP Where JOB = ‘PRESIDENT' or JOB = ‘MANAGER' GROUP JOB |