Oracle Sql语句优化设计(2)

来源:互联网 发布:vscode php插件推荐 编辑:程序博客网 时间:2024/05/11 03:25
(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
高效
SELECTFROM LOCATION WHERE LOC_IN IN(10,20,30);
(26) 避免在索引列上使用ISNULLIS NOTNULL
避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引.对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.举例:如果唯一性索引建立在表的A列和B列上,并且表中存在一条记录的A,B值为(123,null) ,ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入).然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000条具有相同键值的记录,当然它们都是空!因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.
低效:(索引失效)
SELECT FROM  DEPARTMENT WHERE DEPT_CODEIS NOT NULL;
高效:(索引有效)
SELECT FROM  DEPARTMENT WHERE DEPT_CODE>=0;
(27) 总是使用索引的第一个列
如果索引是建立在多个列上,只有在它的第一个列(leading column)where子句引用时,优化器才会选择使用该索引.这也是一条简单而重要的规则,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引
(28) UNION-ALL替换UNION ( 如果有可能的话)
SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序. 如果用UNIONALL替代UNION, 这样排序就不是必要了.效率就会因此得到提高. 需要注意的是UNION ALL将重复输出两个结果集合中相同记录. 因此各位还是要从业务需求分析使用UNIONALL的可行性. UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存.对于这块内存的优化也是相当重要的. 下面的SQL可以用来查询排序的消耗量
低效:
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替代ORDERBY
ORDERBY 子句只在两种严格的条件下使用索引.
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 ORDERBY  DEPT_TYPE
高效:(使用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE> 0
(30) 避免改变索引列的类型.:
当比较不同数据类型的数据时,ORACLE自动对列进行简单的类型转换.
假设EMPNO是一个数值类型的索引列.
SELECT … FROMEMP  WHERE  EMPNO = ‘123‘
实际上,经过ORACLE类型转换,语句转化为:
SELECT … FROMEMP  WHERE EMPNO =TO_NUMBER(‘123‘)
幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.
现在,假设EMP_TYPE是一个字符类型的索引列.
SELECT … FROMEMP  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,ORDERBYSQL语句会启动SQL引擎
执行耗费资源的排序(SORT)功能.DISTINCT需要一次排序操作,而其他的至少需要执行两次排序. 通常,带有UNION,MINUS , INTERSECTSQL语句都可以用其他方式重写.如果你的数据库的SORT_AREA_SIZE调配得好,使用UNION, MINUS, INTERSECT也是可以考虑的,毕竟它们的可读性很强
(34) 优化GROUPBY:
提高GROUP BY语句的效率, 可以通过将不需要的记录在GROUPBY 之前过滤掉.下面两个查询返回相同结果但第二个明显就快了许多.
低效:
SELECT JOB , AVG(SAL)
FROM EMP
GROUPJOB
HAVING JOB =‘PRESIDENT‘
ORJOB = ‘MANAGER‘
高效:
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT‘
OR JOB = ‘MANAGER‘
GROUP JOB
原创粉丝点击