SELECT子句中避免使用 *
当你想在SELECT子句中列出所有的COLUMN时使用动态SQL列引用 * 是一个方便的方法不幸的是这是一个非常低效的方法 实际上ORACLE在解析的过程中 会将* 依次转换成所有的列名 这个工作是通过查询数据字典完成的 这意味着将耗费更多的时间
使用DECODE函数来减少处理时间
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表 例如:
Sql代码
SELECT COUNT(*)SUM(SAL) FROM EMP WHERE DEPT_NO = AND ENAME LIKE SMITH%;
SELECT COUNT(*)SUM(SAL) FROM EMP WHERE DEPT_NO = AND ENAME LIKE SMITH%;
你可以用DECODE函数高效地得到相同结果:
Sql代码
SELECT COUNT(DECODE(DEPT_NOXNULL)) D_COUNT
COUNT(DECODE(DEPT_NOXNULL)) D_COUNT
SUM(DECODE(DEPT_NOSALNULL)) D_SAL
SUM(DECODE(DEPT_NOSALNULL)) D_SAL
FROM EMP WHERE ENAME LIKE SMITH%;
类似的DECODE函数也可以运用于GROUP BY 和ORDER BY子句中
删除重复记录
最高效的删除重复记录方法 ( 因为使用了ROWID)
Sql代码
DELETE FROM EMP E WHERE EROWID > (SELECT MIN(XROWID) FROM EMP X WHERE XEMP_NO = EEMP_NO);
用TRUNCATE替代DELETE
当删除表中的记录时在通常情况下回滚段(rollback segments ) 用来存放可以被恢复的信息如果你没有COMMIT事务ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)而当运用TRUNCATE时 回滚段不再存放任何可被恢复的信息当命令运行后数据不能被恢复因此很少的资源被调用执行时间也会很短
计算记录条数
和一般的观点相反 count(*) 比count()稍快 当然如果可以通过索引检索对索引列的计数仍旧是最快的 例如 COUNT(EMPNO)
用Where子句替换HAVING子句
避免使用HAVING子句HAVING 只会在检索出所有记录之后才对结果集进行过滤这个处理需要排序总计等操作如果能通过WHERE子句限制记录的数目那就能减少这方面的开销 例如:
Sql代码
低效
SELECT REGIONAVG(LOG_SIZE) FROM LOCATION GROUP BY REGION HAVING REGION REGION != SYDNEY AND REGION != PERTH
高效
SELECT REGIONAVG(LOG_SIZE) FROM LOCATION WHERE REGION REGION != SYDNEY ND REGION != PERTH GROUP BY REGION
用EXISTS替代IN
在许多基于基础表的查询中为了满足一个条件往往需要对另一个表进行联接在这种情况下 使用EXISTS(或NOT EXISTS)通常将提高查询的效率
Sql代码
低效
SELECT * FROM EMP WHERE EMPNO > AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = MELB)
高效:
SELECT * FROM EMP WHERE EMPNO > AND EXISTS (SELECT X FROM DEPT WHERE DEPTDEPTNO = EMPDEPTNO AND LOC = MELB)
用NOT EXISTS替代NOT IN
在子查询中NOT IN子句将执行一个内部的排序和合并 无论在哪种情况下NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历) 为了避免使用NOT IN我们可以把它改写成外连接(Outer Joins)或NOT EXISTS 例如:
SELECT …FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=A);
Sql代码
为了提高效率改写为: (方法一: 高效)
SELECT …FROM EMP ADEPT B WHERE ADEPT_NO = BDEPT(+) AND BDEPT_NO IS NULL AND BDEPT_CAT(+) = A
(方法二: 最高效)
SELECT …FROM EMP E WHERE NOT EXISTS (SELECT X FROM DEPT D WHERE DDEPT_NO = EDEPT_NO AND DEPT_CAT = A);
用EXISTS替换DISTINCT
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时避免在SELECT子句中使用DISTINCT 一般可以考虑用EXIST替换
例如:
Sql代码
低效:
SELECT DISTINCT DEPT_NODEPT_NAME FROM DEPT DEMP E WHERE DDEPT_NO = EDEPT_NO
高效:
SELECT DEPT_NODEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT X FROM EMP E WHERE EDEPT_NO = DDEPT_NO);
EXISTS 使查询更为迅速因为RDBMS核心模块将在子查询的条件一旦满足后立刻返回结果
用索引提高效率
索引是表的一个概念部分用来提高检索数据的效率实际上ORACLE使用了一个复杂的自平衡Btree结构通常通过索引查询数据比全表扫描要快当ORACLE找出执行查询和Update语句的最佳路径时 ORACLE优化器将使用索引 同样在联结多个表时使用索引也可以提高效率另一个使用索引的好处是它提供了主键(primary key)的唯一性验证除了那些LONG或LONG RAW数据类型 你可以索引几乎所有的列 通常 在大型表中使用索引特别有效 当然你也会发现 在扫描小表时使用索引同样能提高效率虽然使用索引能得到查询效率的提高但是我们也必须注意到它的代价 索引需要空间来存储也需要定期维护每当有记录在表中增减或索引列被修改时索引本身也会被修改这意味着每条记录的INSERT DELETE UPDATE将为此多付出 次的磁盘I/O 因为索引需要额外的存储空间和处理那些不必要的索引反而会使查询反应时间变慢
注定期的重构索引是有必要的
避免在索引列上使用计算
WHERE子句中如果索引列是函数的一部分优化器将不使用索引而使用全表扫描 举例
Sql代码
低效
SELECT …FROM DEPT WHERE SAL * > ;
高效:
SELECT … FROM DEPT WHERE SAL > /;
用>=替代>
Sql代码
如果DEPTNO上有一个索引
高效
SELECT * FROM EMP WHERE DEPTNO >=
低效
SELECT * FROM EMP WHERE DEPTNO >
两者的区别在于 前者DBMS将直接跳到第一个DEPT等于的记录而后者将首先定位到DEPTNO=的记录并且向前扫描到第一个DEPT大于的记录
通配符% 的使用
不使用索引
select * from emp where name like %A
使用索引
select * from emp where name like A%