【oracle 性能优化】组合索引查询。

简介:
在Oracle中可以创建组合索引,即同时包含两个或两个以上列的索引 组合索引的使用存在着一定的局限,只有在谓词中出现全部索引列时才能使用效率最高的index unique scan, 否则谓词中必须包含前导列,否则会走Index full scan或者FTS。
SQL> create index idx_test on yangtest (object_type,object_name);
索引已创建。
SQL> exec dbms_stats.gather_table_stats(user,'YANGTEST',cascade=>true);
PL/SQL 过程已成功完成。
已用时间:  00: 00: 20.78
SQL> select object_type,count(*) from yangtest group by object_type order by 2;

OBJECT_TYPE           COUNT(*)
------------------- ---------- 
EDITION                      1
RULE                         1
MATERIALIZED VIEW            1 
SCHEDULE                     2 
WINDOW GROUP                 4
DIRECTORY                    5 
UNDEFINED                    6 
LOB PARTITION                7 
RESOURCE PLAN                7 
CONTEXT                      7 
WINDOW                       9
CLUSTER                     10
JOB                         11 
EVALUATION CONTEXT          11 
INDEXTYPE                   11
JOB CLASS                   13
CONSUMER GROUP              14
RULE SET                    17
PROGRAM                     18
QUEUE                       33
OPERATOR                    57
XML SCHEMA                  91
TABLE PARTITION            108 
INDEX PARTITION            128
PROCEDURE                  131
LIBRARY                    179
TYPE BODY                  224
SEQUENCE                   227 
FUNCTION                   296
JAVA DATA                  324
TRIGGER                    482
LOB                        760 
JAVA RESOURCE              833 
PACKAGE BODY              1206
PACKAGE                   1267
TABLE                     2543 
TYPE                      2616
INDEX                     3194 
VIEW                      4749 
JAVA CLASS               22103 
SYNONYM                  26670 

已选择41行。
已用时间:  00: 00: 00.09
1、当使用基于规则的优化器(RBO)时,只有当组合索引的前导列出现在SQL语句的where子句中时,才会使用到该索引;
SQL> set autot trace
SQL> select /*+ rule */ * from yangtest where object_type='JOB';
已选择11行。
已用时间:  00: 00: 00.07
执行计划
----------------------------------------------------------
Plan hash value: 2067289980 
------------------------------------------------ 
| Id  | Operation                   | Name     | 
------------------------------------------------ 
|   0 | SELECT STATEMENT            |          |
|   1 |  TABLE ACCESS BY INDEX ROWID| YANGTEST |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------ 
Predicate Information (identified by operation id):
--------------------------------------------------- 
   2 - access("OBJECT_TYPE"='JOB')
Note       
-----      
   - rule based optimizer used (consider using cbo)
统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets 
         13  consistent gets
          0  physical reads 
          0  redo size   
       2310  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory) 
          0  sorts (disk) 
         11  rows processed 
-- 而让CBO自己选择时,却选择了TFS,从信息统计里面可以看出consistent gets 是前者的100倍。CBO 也不一定很聪明。
SQL> select * from yangtest where object_type='JOB';
已选择11行。
已用时间:  00: 00: 00.03
执行计划
---------------------------------------------------------- 
Plan hash value: 911235955 
------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     | 
------------------------------------------------------------------------------ 
|   0 | SELECT STATEMENT  |          |  1668 |   164K|   275   (1)| 00:00:04 | 
|*  1 |  TABLE ACCESS FULL| YANGTEST |  1668 |   164K|   275   (1)| 00:00:04 | 
------------------------------------------------------------------------------
Predicate Information (identified by operation id):  
---------------------------------------------------  
   1 - filter("OBJECT_TYPE"='JOB')  
统计信息
---------------------------------------------------------- 
        264  recursive calls     
          0  db block gets   
       1050  consistent gets   
          0  physical reads    
          0  redo size        
       2006  bytes sent via SQL*Net to client 
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client 
          0  sorts (memory) 
          0  sorts (disk) 
         11  rows processed
由于使用了组合索引的前导列并且访问了表中的少量记录,Oracle明智地选择了索引扫描。那么,如果我们访问表中的大量数据时,Oracle会选择什么样的访问路径呢?看下面的测试:
SQL> select * from yangtest where object_type='SYNONYM';
已选择26670行。
已用时间:  00: 00: 01.42
执行计划
----------------------------------------------------------
Plan hash value: 911235955
------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |  1668 |   164K|   275   (1)| 00:00:04 | 
|*  1 |  TABLE ACCESS FULL| YANGTEST |  1668 |   164K|   275   (1)| 00:00:04 | 
------------------------------------------------------------------------------ 
Predicate Information (identified by operation id):  
--------------------------------------------------- 
   1 - filter("OBJECT_TYPE"='SYNONYM')
统计信息
---------------------------------------------------------- 
          1  recursive calls 
          0  db block gets  
       2769  consistent gets 
          0  physical reads  
          0  redo size 
    1228701  bytes sent via SQL*Net to client 
      19963  bytes received via SQL*Net from client 
       1779  SQL*Net roundtrips to/from client 
          0  sorts (memory)     
          0  sorts (disk)    
      26670  rows processed 
测试一下是使用RULE 的优化器。
SQL> select /*+ rule */ * from yangtest where object_type='SYNONYM';
已选择26670行。
已用时间:  00: 00: 01.56
执行计划
----------------------------------------------------------                               

                    
Plan hash value: 2067289980 
------------------------------------------------ 
| Id  | Operation                   | Name     | 
------------------------------------------------ 
|   0 | SELECT STATEMENT            |          |
|   1 |  TABLE ACCESS BY INDEX ROWID| YANGTEST |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------
Predicate Information (identified by operation id):
--------------------------------------------------- 
   2 - access("OBJECT_TYPE"='SYNONYM')
Note       
-----      
   - rule based optimizer used (consider using cbo)
统计信息
----------------------------------------------------------
          1  recursive calls  
          0  db block gets  
      23543  consistent gets --明显比cbo的执行计划的多10倍。
          0  physical reads  
          0  redo size      
    3235078  bytes sent via SQL*Net to client   
      19963  bytes received via SQL*Net from client
       1779  SQL*Net roundtrips to/from client   
          0  sorts (memory)    
          0  sorts (disk)    
      26670  rows processed  
  从以上结果可以看出,在访问大量数据的情况下,使用索引确实会导致更高的执行成本,这从statistics部分的逻辑读取数(consistent gets)就可以看出,使用索引导致的逻辑读取数是不使用索引导致的逻辑读的10倍还多。因此,Oracle明智地选择了全表扫描而不是索引扫描。
下面,让我们来看看where子句中没有索引前导列的情况:
SQL> select * from yangtest where object_name ='EMP';
已用时间:  00: 00: 00.01
执行计划
----------------------------------------------------------
Plan hash value: 4208055961
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     2 |   202 |    45   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| YANGTEST |     2 |   202 |    45   (0)| 00:00:01 | 
|*  2 |   INDEX SKIP SCAN           | IDX_TEST |     2 |       |    43   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):   
--------------------------------------------------- 
   2 - access("OBJECT_NAME"='EMP') 
       filter("OBJECT_NAME"='EMP') 
统计信息
---------------------------------------------------------- 
          1  recursive calls  
          0  db block gets  
         35  consistent gets 
          1  physical reads 
          0  redo size    
       1337  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)            
          0  sorts (disk)     
          1  rows processed  

SQL> select * from yangtest where object_name ='YANGTEST';
未选定行
已用时间:  00: 00: 00.01
执行计划
----------------------------------------------------------
Plan hash value: 4208055961 
---------------------------------------------------------------------------------------- 
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     | 
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     2 |   202 |    45   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| YANGTEST |     2 |   202 |    45   (0)| 00:00:01 |
|*  2 |   INDEX SKIP SCAN           | IDX_TEST |     2 |       |    43   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id): 
--------------------------------------------------- 
   2 - access("OBJECT_NAME"='YANGTEST')  
       filter("OBJECT_NAME"='YANGTEST')  
统计信息
---------------------------------------------------------- 
          1  recursive calls   
          0  db block gets     
         27  consistent gets   
          0  physical reads     
          0  redo size         
       1124  bytes sent via SQL*Net to client
        405  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)      
          0  sorts (disk)       
          0  rows processed    

 没有使用前导列,Oracle正确地选择了索引跳跃扫描。我们再来看看如果不使用索引跳跃扫描,该语句的成本:
SQL> select /*+ NO_INDEX(YANGTEST,IDX_TEST)*/ * from yangtest where object_name ='DEPT';
已用时间:  00: 00: 00.01
执行计划
---------------------------------------------------------- 
Plan hash value: 911235955     
------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     2 |   202 |   275   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| YANGTEST |     2 |   202 |   275   (1)| 00:00:04 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):  
---------------------------------------------------
   1 - filter("OBJECT_NAME"='DEPT') 
统计信息
---------------------------------------------------------- 
          1  recursive calls    
          0  db block gets     
       1011  consistent gets  --是使用索引跳跃扫描的50倍左右
          0  physical reads     
          0  redo size         
       1335  bytes sent via SQL*Net to client 
        416  bytes received via SQL*Net from client 
          2  SQL*Net roundtrips to/from client 
          0  sorts (memory)    
          0  sorts (disk)      
          1  rows processed     

SQL> select * from yangtest where object_name like 'T%';
已选择136行。
已用时间:  00: 00: 00.04
执行计划
----------------------------------------------------------
Plan hash value: 911235955     
------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |   925 | 93425 |   275   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| YANGTEST |   925 | 93425 |   275   (1)| 00:00:04 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id): 
--------------------------------------------------- 
   1 - filter("OBJECT_NAME" LIKE 'T%') 
统计信息
----------------------------------------------------------  
          1  recursive calls   
          0  db block gets     
       1020  consistent gets    
          0  physical reads    
          0  redo size         
       8900  bytes sent via SQL*Net to client 
        515  bytes received via SQL*Net from client 
         11  SQL*Net roundtrips to/from client  
          0  sorts (memory)    
          0  sorts (disk)      
        136  rows processed 
 这次只选择了136条数据,跟表YANGTEST中总的数据量29489条相比,显然只是很小的一部分,但是Oracle还是选择了全表扫描,有1020 个逻辑读。这种情况下,如果我们强制使用索引.结果如下
SQL> select /*+ INDEX(YANGTEST,IDX_TEST)*/ * from yangtest where object_name like 'T%';
已选择136行。
已用时间:  00: 00: 00.06
执行计划
----------------------------------------------------------
Plan hash value: 972231820     
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |   925 | 93425 |  1084   (1)| 00:00:14 |
|   1 |  TABLE ACCESS BY INDEX ROWID| YANGTEST |   925 | 93425 |  1084   (1)| 00:00:14 |
|*  2 |   INDEX FULL SCAN           | IDX_TEST |   925 |       |   424   (1)| 00:00:06 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id): 
--------------------------------------------------- 
   2 - access("OBJECT_NAME" LIKE 'T%')
       filter("OBJECT_NAME" LIKE 'T%')
统计信息
---------------------------------------------------------- 
          1  recursive calls    
          0  db block gets     
        537  consistent gets   
          0  physical reads    
          0  redo size         
      14700  bytes sent via SQL*Net to client
        515  bytes received via SQL*Net from client
         11  SQL*Net roundtrips to/from client
          0  sorts (memory)    
          0  sorts (disk)      
        136  rows processed    
通过添加提示(hint),我们强制Oracle使用了索引扫描(index full scan),执行了335个逻辑读,比使用全表扫描的时候少了一些。
    由此可见,Oracle优化器有时会做出错误的选择,因为它再“聪明”,也不如我们SQL语句编写人员更清楚表中数据的分布,在这种情况下,通过使用提示(hint),我们可以帮助Oracle优化器作出更好的选择。
相关文章
|
7天前
|
SQL Oracle 关系型数据库
[Oracle]索引
本文介绍了数据库索引的基本概念、优化查询的原理及分类。索引是一种数据结构(如B树或B+树),通过排序后的`rowid`来优化查询性能。文章详细解释了索引的构建过程、B+树的特点及其优势,并介绍了五种常见的索引类型:唯一索引、组合索引、反向键索引、位图索引和基于函数的索引。每种索引都有其适用场景和限制,帮助读者更好地理解和应用索引技术。
20 1
[Oracle]索引
|
20天前
|
监控 Oracle 关系型数据库
Oracle数据库性能优化
【10月更文挑战第16天】Oracle数据库性能优化是
20 1
|
30天前
|
SQL 监控 Oracle
Oracle SQL性能优化全面指南
在数据库管理领域,Oracle SQL性能优化是确保数据库高效运行和数据查询速度的关键
|
4月前
|
SQL Oracle 关系型数据库
关系型数据库Oracle并行查询
【7月更文挑战第12天】
106 15
|
4月前
|
Oracle 关系型数据库 数据处理
|
4月前
|
SQL 监控 Oracle
|
4月前
|
SQL 监控 Oracle
|
6月前
|
分布式计算 DataWorks 关系型数据库
DataWorks产品使用合集之在 DataWorks 中,使用Oracle作为数据源进行数据映射和查询,如何更改数据源为MaxCompute或其他类型
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
72 1
|
6月前
|
存储 Oracle 关系型数据库
Oracle索引知识看这一篇就足够
Oracle索引知识看这一篇就足够
|
6月前
|
SQL 监控 Oracle
Oracle 性能优化之AWR、ASH和ADDM(含报告生成和参数解读)
Oracle 性能优化之AWR、ASH和ADDM(含报告生成和参数解读)

推荐镜像

更多
下一篇
无影云桌面