以下是最近关于提高ORACLE上SQL执行效率的一些心得:
1、索引
通过索引提高查询效率是非常有效的办法,索引一定要建的合理,并且被正确的使用,因此需要选择合适的列作为索引列
主要有如下规则:
选择在where子句中常用的查询列做索引字段
选择常用来关联表的字段做索引字段
如果索引是建立在多个列上(复合索引),只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引。
create table multiindexusage ( inda number , indb number , descr varchar2(10));
create index multindex on multiindexusage(inda,indb);
通过索引扫描:
select * from multiindexusage where inda = 1;
全表扫描:
select * from multiindexusage where indb = 1;
索引列的类型非常重要,要特别关注。当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换。内部隐式的类型转变会降低执行效率,更重要的是如果转换列为索引列,则由于内部转换(相当于对索引列进行了函数运算)的原因,该索引将不被使用。例如:
select * from user where user_id =123456
若user_id字段类型为字符串型,则oracle自动把上述语句修改为:
select * from user where to_number(user_id) =123456
注意:当字符和数值比较时, ORACLE会优先转换数值类型到字符类型,则user_id列上的索引失效。为了使用索引最好做显示的类型转换,修改为:
select * from user where user_id =to_char(123456)
由于类型转换也要耗费时间,最好避免,修改为:
select * from user where user_id =‘123456’
2、执行的先后顺序
表名的顺序
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理。
在FROM子句中包含多个表的情况下,应该选择记录条数最少的表作为基础表。当ORACLE处理多个表时,会运用排序及合并的方式连接它们。首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。
如果有3个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。
where子句的顺序
ORACLE采用自下而上的顺序解析WHERE子句,表之间的连接应该写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件应该写在WHERE子句的末尾。
例如:
SELECT
…
FROM
EMP E
WHERE
SAL > 50000 AND JOB =‘MANAGER’
AND 25 <
(
SELECT
COUNT(*)
FROM
EMP
WHERE
MGR=E.EMPNO
)
应改为:
SELECT
…
FROM
EMP E
WHERE
25 <
(
SELECT
COUNT(*)
FROM
EMP
WHERE
MGR=E.EMPNO
) AND SAL > 50000 AND JOB =‘MANAGER’
提高GROUP BY语句的效率,可以通过将不需要的记录在GROUP BY之前过滤掉。
低效:
SELECT
JOB , AVG(SAL)
FROM
EMP
GROUP BY
JOB
HAVING JOB =‘PRESIDENT' OR JOB =‘MANAGER'
高效:
SELECT
JOB , AVG(SAL)
FROM
EMP
WHERE
JOB =‘PRESIDENT' OR JOB =‘MANAGER'
GROUP BY
JOB