4.1 使用不等于操作符(<>、!=) 下面的查询即使在cust_rating列有一个索引,查询语句仍然执行一次全表扫描。 select cust_Id,cust_name from customers where cust_rating <> 'aa'; 把上面的语句改成如下的查询语句,这样,在采用基于规则的优化器而不是基于代价的优化器(更智能)时,将会使用索引。 select cust_Id,cust_name from customers where cust_rating < 'aa' or cust_rating > 'aa'; 特别注意:通过把不等于操作符改成OR条件,就可以使用索引,以避免全表扫描。
4.2 使用IS NULL 或IS NOT NULL 使用IS NULL 或IS NOT NULL同样会限制索引的使用。因为NULL值并没有被定义。在SQL语句中使用NULL会有很多的麻烦。因此建议开 发人员在建表时,把需要索引的列设成NOT NULL。如果被索引的列在某些行中存在NULL值,就不会使用这个索引(除非索引是一个位图索 引,关于位图索引在稍后在详细讨论)。
4.3 使用函数 如果不使用基于函数的索引,那么在SQL语句的WHERE子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。 下面的查询不会使用索引(只要它不是基于函数的索引) select empno,ename,deptno from emp where trunc(hiredate)='01-MAY-81'; 把上面的语句改成下面的语句,这样就可以通过索引进行查找。 select empno,ename,deptno from emp where hiredate<(to_date('01-MAY-81')+0.9999);
4.4 比较不匹配的数据类型 比较不匹配的数据类型也是比较难于发现的性能问题之一。 注意下面查询的例子,account_number是一个VARCHAR2类型,在account_number字段上有索引。下面的语句将执行全表扫描。 select bank_name,address,city,state,zip from banks where account_number = 990354; Oracle可以自动把where子句变成to_number(account_number)=990354,这样就限制了索引的使用,改成下面的查询就可以使用索引: select bank_name,address,city,state,zip from banks where account_number ='990354'; 特别注意:不匹配的数据类型之间比较会让Oracle自动限制索引的使用,即便对这个查询执行Explain Plan也不能让您明白为什么做了一 次“全表扫描”。
[8] 快速全局扫描 在Oracle7.3后就可以使用快速全局扫描(Fast Full Scan)这个选项。这个选项允许Oracle执行一个全局索引扫描操作。快速全局扫描读取B-树索引上所有树叶块。初始化文件中的DB_FILE_MULTIBLOCK_READ_COUNT参数可以控制同时被读取的块的数目。
[9] 跳跃式扫描 从Oracle9i开始,索引跳跃式扫描特性可以允许优化器使用组合索引,即便索引的前导列没有出现在WHERE子句中。索引跳跃式扫描比全索引扫描要快的多。下面的程序清单显示出性能的差别: create index skip1 on emp5(job,empno); index created.
select count(*) from emp5 where empno=7900;
Elapsed:00:00:03.13
Execution Plan 0 SELECT STATEMENT Optimizer=CHOOSE(Cost=4 Card=1 Bytes=5) 1 0 SORT(AGGREGATE) 2 1 INDEX(FAST FULL SCAN) OF 'SKIP1'(NON-UNIQUE)
Statistics
6826 consistent gets 6819 physical reads
select /*+ index(emp5 skip1)*/ count(*) from emp5 where empno=7900;
Elapsed:00:00:00.56
Execution Plan 0 SELECT STATEMENT Optimizer=CHOOSE(Cost=6 Card=1 Bytes=5) 1 0 SORT(AGGREGATE) 2 1 INDEX(SKIP SCAN) OF 'SKIP1'(NON-UNIQUE)