Oracle中常数复合索引的应用案例

从一个客户的真实优化案例引申的问题。

客户的一个数据库需要进行优化,不过由于程序开发方没有介入,因此这次优化无法对SQL进行修改。

仅对数据库级的调整一般来说收效不大,不过发现客户数据库中个别的SQL存在性能问题,且这个性能问题已经影响到整个数据库。如果可以将这个SQL优化,那么可以解决目前数据库的性能问题。幸运的是,这个问题可以通过添加索引来进行优化。

模拟问题SQL如下:

SQL> select * from v$version;

BANNER

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

Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

PL/SQL Release 9.2.0.4.0 - Production

CORE   9.2.0.3.0      Production

TNS for Linux: Version 9.2.0.4.0 - Production

NLSRTL Version 9.2.0.4.0 – Production

SQL> create table t (id number not null, created date, other char(200));

Table created.

SQL> insert into t select rownum, created, 'a' from all_objects;

31126 rows created.

SQL> commit;

Commit complete.

SQL> exec dbms_stats.gather_table_stats(user, 'T')

PL/SQL procedure successfully completed.

SQL> var v_id number

SQL> var v_date varchar2(14)

SQL> explain plan for

2 select count(*)

3 from t

4 where nvl(created, sysdate) > to_date(:v_date, 'yyyymmddhh24miss') - 3

5 and id = :v_id;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

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

| Id | Operation           | Name      | Rows | Bytes | Cost |

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

|  0 | SELECT STATEMENT    |            |    1 |   13 |   92 |

|  1 | SORT AGGREGATE     |            |    1 |   13 |      |

|* 2 |  TABLE ACCESS FULL | T          |    1 |   13 |   92 |

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

Predicate Information (identified by operation id):

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

2 - filter(NVL("T"."CREATED",SYSDATE@!)>TO_DATE(:Z,'yyyymmddhh24miss')-3 AND "T"."ID"=TO_NUMBER(:Z))

Note: cpu costing is off

16 rows selected.

对于这个SQL,通过索引方式优化很简单,只需要建立ID和CREATED上的复合索引,就可以避免全表扫描:

SQL> create index ind_t_id_created on t (id, created);

Index created.

SQL> explain plan for

2 select count(*)

3 from t

4 where nvl(created, sysdate) > to_date(:v_date, 'yyyymmddhh24miss') - 3

5 and id = :v_id;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

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

| Id | Operation           | Name            | Rows | Bytes | Cost |

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

|  0 | SELECT STATEMENT    |                  |    1 |   13 |    2 |

|  1 | SORT AGGREGATE     |                  |    1 |   13 |      |

|* 2 |  INDEX RANGE SCAN  | IND_T_ID_CREATED |    1 |   13 |    2 |

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

返回栏目页:http://www.bianceng.cnhttp://www.bianceng.cn/database/Oracle/

Predicate Information (identified by operation id):

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

2 - access("T"."ID"=TO_NUMBER(:Z))

filter(NVL("T"."CREATED",SYSDATE@!)>TO_DATE(:Z,'yyyymmddhh24miss')-3)

Note: cpu costing is off

17 rows selected.

Oracle之所以可以选择索引扫描,是由于复合索引中CREATED列为空的记录也会被保存。由于ID列为非空,而索引不会保存所有列全为空的情况,因此CREATED为空的记录同样可以在索引中找到。

事实上,即使ID不为空,由于另一个查询条件指定了ID = :V_ID,这使得访问的记录并不包括ID为空的记录,这使得复合索引仍然可以包括这个SQL需要访问的所有数据。

不过新的疑问来了,如果查询的SQL不包含ID列的限制条件,则目前的索引不在可用:

SQL> alter table t modify id null;

Table altered.

SQL> explain plan for

2 select count(*)

3 from t

4 where nvl(created, sysdate) > to_date(:v_date, 'yyyymmddhh24miss') - 3;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

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

时间: 2024-09-19 08:57:27

Oracle中常数复合索引的应用案例的相关文章

MySQL和Oracle中的唯一性索引从差别(r12笔记第83天)

   今天在修复MySQL数据的时候,发现一个看起来"奇怪"的问题.   有一个表里存在一个唯一性索引,这个索引包含3个列,这个唯一性索引的意义就是通过这3个列能够定位到具体1行的数据,但是在实际中却发现这个唯一性索引还是有一个地方可能被大家忽略了.  我们先来看看数据的情况.  CREATE TABLE `test_base_data` (   `servertime` datetime DEFAULT NULL COMMENT '时间',   `appkey` varchar(64

Oracle中如何管理索引组织表

索引组织表(IOT)有一种类B树的存储组织方法.普通的堆组织表是以一种无序的集合存储.而IOT中的数据是按主键有序的存储在B树索引结构中.与一般B树索引不同的的是,在IOT中每个叶结点即有每行的主键列值,又有那些非主键列值. 在IOT所对应的B树结构中,每个索引项包括<主键列值,非主键列值>而不是ROWID,对于普通堆组织表,oracle会有对应的索引与之对应,且分开存储.换句话说,IOT即是索引,又是实际的数据. 索引组织表(IOT)不仅可以存储数据,还可以存储为表建立的索引.索引组织表的数

Oracle中查看建立索引和使用索引的注意点

一.查看和建立索引 select * from user_indexes where table_name = 'student' create index i_student_num on student(num) 二.使用索引的注意点 ①类型匹配 若student中num列是varchar类型,语句select * from student where num = 100 该语句被转化为select * from student where to_number(num) = 100,该列的索

查询中让优化器使用复合索引

-- Create table create table MT_BIZ (   HOSPITAL_ID      VARCHAR2(20) not null,   SERIAL_NO        VARCHAR2(16) not null,   FEE_BATCH        NUMBER(5) default 1 not null,   CASE_ID          NUMBER(12),   BIZ_TYPE         VARCHAR2(2) not null,   ORDIN

MongoDB 复合索引

MongoDB支持复合索引,即将多个键组合到一起创建索引.该方式称为复合索引,或者也叫组合索引,该方式能够满足多键值匹配查询使用索引的情形.其次复合索引在使用的时候,也可以通过前缀法来使用索引.MongoDB中的复合索引与关系型数据库基本上一致.在关系型数据库中复合索引使用的一些原则同样适用于MongoDB.本文主要描述MongoDB复合索引. 一.复合索引相关概述 1.复合索引创建语法 db.collection.createIndex( { <field1>: <type>,

Oracle中含常数的复合索引

原来对于索引的认识只知道索引可以基于一个或者多个列,B-Tree索引不包含null,但有些情况下我们又需要通过where 列名 is null来查找一些数据,这时候数据库由于没办法使用索引就会使用全表扫描,导致执行效率低下,这时候我们可以通过使用含常数的复合索引来解决这个问题. 下面开始进行实验: 首先建立测试表 SYS@ORCL>create table test_objects nologging as select rownum id,a.* from dba_objects a wher

oracle中复合索引的创建剖析—包含in的三个条件SQL语句复合索引的创建

之前文章中提过复合索引的创建思路: 1 前导列尽可能让更多的核心业务SQL能够使用 2 单个SQL语句索引的前导列尽量选择等值条件做为索引的前导列 这里我们如果在对in的谓词.三个条件的SQL语句复合索引的创建做一些更深入的分析,详细的例子如下: SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle D

oracle中OBJ4 ORA-8102故障恢复案例

  下面我们一起来看看关于oracle中OBJ4 ORA-8102故障恢复案例,希望本文章可以帮助到各位朋友. 在测试环境中对于OBJ$中i_obj4中出现ORA-8102进行了重新并恢复测试,认为自己已经比较清楚的掌握了I_OBJ4的ORA-8102问题处理,可是实际的一个案例,还是比较比实验中复杂,这里贴出来主要操作供大家参考,再次证明数据库恢复的场景不可大意,客户的故障只有你想不到的,没有遇不到的 通过bbed修改obj$中dataobj$重现I_OBJ4索引报ORA-08102错误 使用

[数据库]Oracle中如果对“性别”这样的字段建立索引

oracle|数据|数据库|索引 由于"性别"这样的字段中的变化值很少,建立不同的Normal索引是毫无用处的.但我们在查询中还是会经常用的检索"性别为男的大于30岁"这样的条件,如果不加索引在数据量加大的时候还是会很慢,其实,Oracle中对此是有解决办法的,那就是Bitmap类型索引,我实验发现加了这种类型索引后,速度可以大大提高.