`

oracle 组合索引使用

 
阅读更多
在Oracle中可以创建组合索引,即同时包含两个或两个以上列的索引。在组合索引的使用方面,Oracle有以下特点:

    1、 当使用基于规则的优化器(RBO)时,只有当组合索引的前导列出现在SQL语句的where子句中时,才会使用到该索引;

    2、 在使用Oracle9i之前的基于成本的优化器(CBO)时, 只有当组合索引的前导列出现在SQL语句的where子句中时,才可能会使用到该索引,这取决于优化器计算的使用索引的成本和使用全表扫描的成本,Oracle会自动选择成本低的访问路径(请见下面的测试1和测试2);

    3、 从Oracle9i起,Oracle引入了一种新的索引扫描方式——索引跳跃扫描(index skip scan),这种扫描方式只有基于成本的优化器(CBO)才能使用。这样,当SQL语句的where子句中即使没有组合索引的前导列,并且索引跳跃扫描的成本低于其他扫描方式的成本时,Oracle就会使用该方式扫描组合索引(请见下面的测试3);

    4、 Oracle优化器有时会做出错误的选择,因为它再“聪明”,也不如我们SQL语句编写人员更清楚表中数据的分布,在这种情况下,通过使用提示(hint),我们可以帮助Oracle优化器作出更好的选择(请见下面的测试4)。

    关于以上情况,我们分别测试如下:

    我们创建测试表T,该表的数据来源于Oracle的数据字典表all_objects,表T的结构如下:

SQL> desc t

名称 是否为空? 类型

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

OWNER NOT NULL VARCHAR2(30)

OBJECT_NAME NOT NULL VARCHAR2(30)

SUBOBJECT_NAME VARCHAR2(30)

OBJECT_ID NOT NULL NUMBER

DATA_OBJECT_ID NUMBER

OBJECT_TYPE VARCHAR2(18)

CREATED NOT NULL DATE

LAST_DDL_TIME NOT NULL DATE

TIMESTAMP VARCHAR2(19)

STATUS VARCHAR2(7)

TEMPORARY VARCHAR2(1)

GENERATED VARCHAR2(1)

SECONDARY VARCHAR2(1)


表中的数据分布情况如下:

SQL> select object_type,count(*) from t group by object_type;

OBJECT_TYPE COUNT(*)

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

CONSUMER GROUP 20

EVALUATION CONTEXT 10

FUNCTION 360

INDEX 69

LIBRARY 20

LOB 20

OPERATOR 20

PACKAGE 1210

PROCEDURE 130

SYNONYM 16100

TABLE 180

TYPE 2750

VIEW 8600

已选择13行。

SQL> select count(*) from t;

COUNT(*)

----------

29489

    我们在表T上创建如下索引并对其进行分析:

SQL> create index indx_t on t(object_type,object_name);

索引已创建。

SQL> ANALYZE TABLE T COMPUTE STATISTICS

2 FOR TABLE

3 FOR ALL INDEXES

4 FOR ALL INDEXED COLUMNS

5 /

表已分析。

现在让我们编写几条SQL语句来测试一下Oracle优化器对访问路径的选择:

    测试1)

SQL> set autotrace traceonly

SQL> SELECT * FROM T WHERE OBJECT_TYPE='LOB';

已选择20行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=22 Card=20 Bytes=1740)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=22 Card=20 Bytes=1740)

2 1 INDEX (RANGE SCAN) OF 'INDX_T' (NON-UNIQUE) (Cost=2 Card=20)

    正如我们所期望的,由于使用了组合索引的前导列并且访问了表中的少量记录,Oracle明智地选择了索引扫描。那么,如果我们访问表中的大量数据时,Oracle会选择什么样的访问路径呢?请看下面的测试:


    测试2)

SQL> SELECT * FROM T WHERE OBJECT_TYPE='SYNONYM';

已选择16100行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=38 Card=16100 Bytes=1400700)

1 0 TABLE ACCESS (FULL) OF 'T' (Cost=38 Card=16100 Bytes=1400700)

Statistics

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

0 recursive calls

0 db block gets

1438 consistent gets

13 physical reads

0 redo size

941307 bytes sent via SQL*Net to client

12306 bytes received via SQL*Net from client

1075 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

16100 rows processed

    很明显,即使使用了组合索引的前导列,但是由于访问了表中的大量数据,Oracle选择了不使用索引而直接使用全表扫描,因为优化器认为全表扫描的成本更低,但事实是不是真的这样的?我们通过增加提示(hint)来强制它使用索引来看看:


SQL> SELECT/**//*+ INDEX (T INDX_T)*/ * FROM T WHERE OBJECT_TYPE='SYNONYM';

已选择16100行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=16180 Card=16100 Bytes=1400700)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=16180 Card=16100 Bytes=1400700)

2 1 INDEX (RANGE SCAN) OF 'INDX_T' (NON-UNIQUE) (Cost=80 Card=16100)

Statistics

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

0 recursive calls

0 db block gets

17253 consistent gets

16 physical reads

0 redo size

298734 bytes sent via SQL*Net to client

12306 bytes received via SQL*Net from client

1075 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

16100 rows processed

    从以上结果可以看出,在访问大量数据的情况下,使用索引确实会导致更高的执行成本,这从statistics部分的逻辑读取数(consistent gets)就可以看出,使用索引导致的逻辑读取数是不使用索引导致的逻辑读的10倍还多。因此,Oracle明智地选择了全表扫描而不是索引扫描。

下面,让我们来看看where子句中没有索引前导列的情况:


    测试3)


SQL> select * from t where object_name= 'DEPT';

已选择10行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=29 Card=14 Bytes=1218)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=29 Card=14 Bytes=1218)

2 1 INDEX (SKIP SCAN) OF 'INDX_T' (NON-UNIQUE) (Cost=14 Card=14)

Statistics

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

0 recursive calls

0 db block gets

24 consistent gets

0 physical reads

0 redo size

1224 bytes sent via SQL*Net to client

503 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

10 rows processed

    OK!由于只查询了10条数据,即使没有使用前导列,Oracle正确地选择了索引跳跃扫描。我们再来看看如果不使用索引跳跃扫描,该语句的成本:

SQL> select/**//*+ NO_INDEX(T INDX_T)*/ * from t where object_name= 'DEPT';

已选择10行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=38 Card=14 Bytes=1218)

1 0 TABLE ACCESS (FULL) OF 'T' (Cost=38 Card=14 Bytes=1218)

Statistics

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

0 recursive calls

0 db block gets

375 consistent gets

17 physical reads

0 redo size

1224 bytes sent via SQL*Net to client

503 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

10 rows processed

    正如我们所料,不使用索引所导致的逻辑读(375)确实比使用索引的逻辑读多(24),达到10倍以上。

继续我们的测试,现在我们来看看Oracle不选择使用索引的情况:


    测试4)

SQL> select * from t where object_name LIKE 'DE%';

已选择180行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=38 Card=37 Bytes=3219)

1 0 TABLE ACCESS (FULL) OF 'T' (Cost=38 Card=37 Bytes=3219)

Statistics

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

0 recursive calls

0 db block gets

386 consistent gets

16 physical reads

0 redo size

12614 bytes sent via SQL*Net to client

624 bytes received via SQL*Net from client

13 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

180 rows processed

    这次只选择了180条数据,跟表T中总的数据量29489条相比,显然只是很小的一部分,但是Oracle还是选择了全表扫描,有386个逻辑读。这种情况下,如果我们强制使用索引,情况会怎样呢?

SQL> select/**//*+ INDEX(T INDX_T)*/ * from t where object_name LIKE 'DE%';

已选择180行。

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=182 Card=37 Bytes=3219)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=182 Card=37 Bytes=3219)

2 1 INDEX (FULL SCAN) OF 'INDX_T' (NON-UNIQUE) (Cost=144 Card=37)

Statistics

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

0 recursive calls

0 db block gets

335 consistent gets

0 physical reads

0 redo size

4479 bytes sent via SQL*Net to client

624 bytes received via SQL*Net from client

13 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

180 rows processed

    通过添加提示(hint),我们强制Oracle使用了索引扫描(index full scan),执行了335个逻辑读,比使用全表扫描的时候少了一些。

    由此可见,Oracle优化器有时会做出错误的选择,因为它再“聪明”,也不如我们SQL语句编写人员更清楚表中数据的分布,在这种情况下,通过使用提示(hint),我们可以帮助Oracle优化器作出更好的选择。

分享到:
评论

相关推荐

    Oracle 创建索引的基本规则

    - **监控索引使用情况**: 使用Oracle的工具如AWR报告来监控索引的使用情况,识别未被充分利用的索引并进行调整。 - **避免频繁修改索引列**: 对索引列频繁进行UPDATE、INSERT或DELETE操作会导致索引碎片化,影响性能...

    Oracle索引优化

    然而,Oracle9i引入了跳跃式扫描,允许在不使用前导列的情况下使用组合索引。 ROWID是Oracle中每个行的唯一标识,它提供了直接访问单行数据的能力。通过ROWID,可以快速定位到数据行,这对于数据检索非常有用。然而...

    oracle约束和索引笔记

    Oracle数据库是世界上最广泛使用的数据库管理系统之一,其在数据管理和性能优化方面有着强大的功能。本笔记主要探讨了两个关键概念:约束和索引,这些都是Oracle数据库中的基础但至关重要的元素。 **1. 约束...

    09 oracle的索引 PPT

    - Bitmap索引:适用于多列组合索引和在低基数(非唯一或重复值多)的列上,适合联接操作和分析查询。 - Function-Based索引:基于函数的结果创建索引,索引列是函数的输出。 - Reverse索引:反向键索引,用于存储...

    Oracle索引优化相关

    **特别注意**:在Oracle 9i及以前的版本中,组合索引只能在使用其前导索引列的情况下才能被有效地利用。 #### 三、Oracle ROWID ROWID是一种特殊的索引形式,它实际上是一个指向表中每一行物理位置的地址。通过...

    oracle的索引学习

    本篇文章将深入探讨Oracle索引的学习,重点关注索引的原理、类型、优缺点以及如何使用和分析执行计划。 首先,理解索引的基本概念。索引是一种特殊的数据结构,它存储在表空间中,用于加速对表数据的访问。当执行...

    oracle不走索引可能原因.docx

    1. **INDEX SKIP SCAN**: 当创建了一个组合索引,但是查询只使用了索引的非第一列时,Oracle可能会选择不使用索引,因为它无法直接通过索引来定位数据。INDEX SKIP SCAN是一种优化策略,允许数据库跳过索引的第一个...

    oracle索引机制分析

    组合索引的使用方法 - **定义**:组合索引是指在一个索引中包含了多个列。这种方式可以支持包含多个列的WHERE子句。 - **优点**:组合索引可以减少索引的数量,提高查询效率,特别是在复杂的查询条件下。 - **创建...

    Oracle索引机制分析

    但是,如果查询条件中只涉及到组合索引的部分列,那么索引可能无法完全利用,这称为部分索引覆盖,可能导致全索引扫描。 **直方图**是Oracle用来估计数据分布的一种手段,尤其在统计分析和索引优化中起到重要作用,...

    Oracle优化全攻略一【Oracle 索引概念】.docx

    在Oracle9i之前,除非查询中包含索引的第一列,否则无法使用组合索引。但在Oracle9i之后,引入了跳跃式扫描,使得即使不包含第一列,也能部分利用组合索引。 通过ROWID,Oracle能直接定位到表中的每一行。ROWID是一...

    为什么oracle有时不用索引来查找数据

    2. **索引列的使用**:索引列或组合索引的首列必须出现在SQL语句的WHERE子句中,这是执行计划能够使用相关索引的必要条件之一。 3. **连接类型**:Oracle支持三种连接方式:排序合并连接(Sort Merge Join, SMJ)、...

    oracle 索引创建.ppt

    - **复合索引**:对于多列查询,可以创建复合索引,将多个列组合在一起,提高查询效率。索引顺序应根据查询条件的频率和选择性进行优化。 - **覆盖索引(Covering Index)**:如果索引包含了查询所需的所有列,那么...

    Oracle强制索引

    - **描述**:此提示用于组合多个索引。 - **应用场景**: - 当需要结合多个索引来优化查询时使用。 - 示例:`SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/* FROM BSEMPMS WHERE SAL - **解释**:此...

    Oracle 索引

    因此,合理地使用和管理索引对于数据库性能至关重要。 Oracle还提供了自适应索引策略,根据查询的执行计划动态选择最合适的索引。此外,索引统计信息的准确性和及时更新也是确保索引有效性的关键。`DBMS_STATS`包...

    ORacle、索引、数据优化学习文档

    在数据优化方面,合理使用索引可以极大地提高查询效率,但也需要根据具体场景选择合适的索引类型,如单列索引、组合索引和位图索引。组合索引允许在多列上创建索引,以匹配多条件查询,而位图索引则适合于数据重复...

    最全的Oracle中文使用手册

    这只是一个起点,Oracle的深度和广度远不止于此,包括索引、视图、触发器、存储过程、性能优化等方面都有大量知识等待探索。对于开发者和DBA来说,掌握Oracle的使用是提升工作效率和解决问题的关键。

    Oracle培训 关于索引等详细信息的讲解

    在Oracle中,可以使用CREATE INDEX语句创建索引,例如: ```sql CREATE INDEX idx_employee_name ON employees(last_name); ``` 索引的维护包括监控索引的使用情况、分析索引碎片、重建索引等。Oracle提供了DBMS_...

    oracle 视图、索引(自用)

    3. 索引监控:通过性能监控工具检查索引使用情况,判断是否需要调整或删除。 4. 索引优化:考虑使用索引合并、覆盖索引、分区策略等技术来进一步优化查询性能。 总结来说,Oracle视图提供了数据抽象和安全控制的...

Global site tag (gtag.js) - Google Analytics