ORACLE SQL性能优化系列 (十三)

oracle|性能|优化

43.       用WHERE替代ORDER BY

ORDER BY 子句只在两种严格的条件下使用索引.

 

ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.

ORDER BY中所有的列必须定义为非空.

 

WHERE子句使用的索引和ORDER BY子句中所使用的索引不能并列.

 

例如:

      表DEPT包含以下列:

 

        DEPT_CODE    PK    NOT NULL

        DEPT_DESC           NOT NULL

        DEPT_TYPE           NULL

   

       非唯一性的索引(DEPT_TYPE)

 

     低效: (索引不被使用)

            SELECT DEPT_CODE

            FROM DEPT

            ORDER BY DEPT_TYPE

 

       EXPLAIN PLAN:

            SORT ORDER BY

                  TABLE ACCESS FULL

 

     高效: (使用索引)

 

           SELECT DEPT_CODE

           FROM DEPT

        WHERE DEPT_TYPE > 0

  

 EXPLAIN PLAN:

      TABLE ACCESS BY ROWID ON EMP

             INDEX RANGE SCAN ON DEPT_IDX

译者按:

      ORDER BY 也能使用索引! 这的确是个容易被忽视的知识点. 我们来验证一下:

SQL>  select * from emp order by empno;

Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (FULL SCAN) OF 'EMPNO' (UNIQUE)

 

44.       避免改变索引列的类型.

当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换.

 

假设 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

WHERE TO_NUMBER(EMP_TYPE)=123

 

因为内部发生的类型转换, 这个索引将不会被用到!

译者按:

为了避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE会优先转换数值类型到字符类型.

 

45.       需要当心的WHERE子句

某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子.

在下面的例子里, ‘!=’ 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中.

不使用索引:

SELECT ACCOUNT_NAME

FROM TRANSACTION

WHERE AMOUNT !=0;

使用索引:

SELECT ACCOUNT_NAME

FROM TRANSACTION

WHERE AMOUNT >0;

 

下面的例子中, ‘||’是字符连接函数. 就象其他函数那样, 停用了索引.

不使用索引:

SELECT ACCOUNT_NAME,AMOUNT

FROM TRANSACTION

WHERE ACCOUNT_NAME||ACCOUNT_TYPE=’AMEXA’;

使用索引:

SELECT ACCOUNT_NAME,AMOUNT

FROM TRANSACTION

WHERE ACCOUNT_NAME = ‘AMEX’

AND  ACCOUNT_TYPE=’ A’;

 

下面的例子中, ‘+’是数学函数. 就象其他数学函数那样, 停用了索引.

不使用索引:

SELECT ACCOUNT_NAME, AMOUNT

FROM TRANSACTION

WHERE AMOUNT + 3000 >5000;

使用索引:

SELECT ACCOUNT_NAME, AMOUNT

FROM TRANSACTION

WHERE AMOUNT > 2000 ;

下面的例子中,相同的索引列不能互相比较,这将会启用全表扫描.

不使用索引:

SELECT ACCOUNT_NAME, AMOUNT

FROM TRANSACTION

WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME);

使用索引:

SELECT ACCOUNT_NAME, AMOUNT

FROM TRANSACTION

WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,’%’);

 

译者按:

如果一定要对使用函数的列启用索引, ORACLE新的功能: 基于函数的索引(Function-Based Index) 也许是一个较好的方案.

 CREATE INDEX EMP_I ON EMP (UPPER(ename)); /*建立基于函数的索引*/

 SELECT * FROM emp WHERE UPPER(ename) = ‘BLACKSNAIL’; /*将使用索引*/

时间: 2024-08-03 05:22:51

ORACLE SQL性能优化系列 (十三)的相关文章

ORACLE SQL性能优化系列 (十四) 完结篇

oracle|性能|优化 46.       连接多个扫描 如果你对一个列和一组有限的值进行比较, 优化器可能执行多次扫描并对结果进行合并连接. 举例:     SELECT *     FROM LODGING     WHERE MANAGER IN ('BILL GATES','KEN MULLER');       优化器可能将它转换成以下形式     SELECT *     FROM LODGING     WHERE MANAGER = 'BILL GATES'     OR MA

ORACLE SQL性能优化系列 (二)

oracle|性能|优化 4. 选择最有效率的表名顺序(只在基于规则的优化器中有效) ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二

ORACLE SQL性能优化系列 (一)

oracle|性能|优化 1. 选用适合的ORACLE优化器      ORACLE的优化器共有3种:    a.  RULE (基于规则)   b. COST (基于成本)  c. CHOOSE (选择性)      设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖.    为了使用基于成本的优化器(CBO,

ORACLE SQL性能优化系列 (八)

oracle|性能|优化 25.       用索引提高效率   索引是表的一个概念部分,用来提高检索数据的效率. 实际上,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证. 除了那些LONG或LONG RAW数据类型, 你可以索引几乎所有的列

ORACLE SQL性能优化系列 (九)

oracle|性能|优化 27.       基础表的选择   基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的. 如果你使用的是CBO (COST BASED OPTIMIZER),优化器会检查SQL语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径. 如果你用RBO (RULE BASED OPTIMIZER) , 并且所有的连接条件都有索引对应, 在这种情况下, 基础表就是FROM

ORACLE SQL性能优化系列 (十)

oracle|性能|优化 31.       强制索引失效      如果两个或以上索引具有相同的等级,你可以强制命令ORACLE优化器使用其中的一个(通过它,检索出的记录数量少) .   举例:    SELECT ENAME FROM EMP WHERE EMPNO = 7935  AND DEPTNO + 0 = 10    /*DEPTNO上的索引将失效*/ AND EMP_TYPE || '' = 'A'  /*EMP_TYPE上的索引将失效*/   这是一种相当直接的提高查询效率的办

ORACLE SQL性能优化系列 (十一)

oracle|性能|优化 36.       用UNION替换OR (适用于索引列) 通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.    在下面的例子中, LOC_ID 和REGION上都建有索引. 高效:    SELECT LOC_ID , LOC_DESC , REGION    FROM LOCATION    W

ORACLE SQL性能优化系列 (十二)

oracle|性能|优化 39.       总是使用索引的第一个列 如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引.   译者按: 这也是一条简单而重要的规则. 见以下实例.   SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10)); Table created. SQL> create index

ORACLE SQL性能优化系列 (七)

oracle|性能|优化 24.       用EXPLAIN PLAN 分析SQL语句   EXPLAIN PLAN 是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句. 通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称. 你需要按照从里到外,从上到下的次序解读分析的结果. EXPLAIN PLAN分析的结果是用缩进的格式排列的, 最内部的操作将被最先解读, 如果两个操作处于同一层中,带有最小操作号的将被首