查询不使用复合索引-为什么?

时间:2018-12-28 16:02:06

标签: oracle query-optimization

我有一个查询

select a.id,
       a.code,
       h.history_id
from a
join h
  on h.object_id = a.id
and h.level = 'Level1'
and h.class_id in ('class1', 'class2');

及其执行计划:

 -----------------------------------------------------------------------------------
    | Id  | Operation                     | Name  | Rows  | Bytes | Cost   | Time     |
    -----------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |       |   340 |108889 | 794224 | 00:00:32 |
    |  *1 |  HASH JOIN                    |       |   340 |108889 | 794224 | 00:00:32 |
    |   2 |   TABLE ACCESS STORAGE FULL   |     a |   340 | 39314 |      2 | 00:00:01 |
    |   3 |   PARTITION RANGE ALL         |       | 274564| 54855 |  69422 | 00:00:32 |
    |  *4 |    TABLE ACCESS STORAGE FULL  |     h | 274564| 54855 |  69422 | 00:01:14 |
    -----------------------------------------------------------------------------------

*1 - access("a"."id" = "h"."object_id")
*4 - storage ("h"."level" = 'Level1' and ("h"."class_id" = 'class1' or "h"."class_id" = 'class2'))
*4 - filter ("h"."level" = 'Level1' and ("h"."class_id" = 'class1' or "h"."class_id" = 'class2'))

在表上也有索引-在表a(id)上,在表h(object_id,level,class_id)上有复合索引。 统计信息也被收集。

表a包含约340条记录,表h包含约10亿条记录。 结果查询返回约200行

尽管表h的索引中的所有列都在联接条件下使用,但根据计划,在列级别和class_id上没有访问谓词。 我不明白这种解决方案。

我希望至少h.level处于访问谓词中。 有什么解决办法吗?还是某种查询重写?

1 个答案:

答案 0 :(得分:0)

基于该语句,查询结果只有200行,应使用索引。

使用综合数据(最简单的情况,OBJECT_ID在表H中是唯一的),您应该看到此执行计划

Plan hash value: 3146900768

--------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |      1 |        |    200 |00:00:00.04 |      40 |      4 |
|   1 |  NESTED LOOPS                |      |      1 |      2 |    200 |00:00:00.03 |      40 |      4 |
|   2 |   NESTED LOOPS               |      |      1 |    340 |    200 |00:00:00.02 |      36 |      3 |
|   3 |    TABLE ACCESS FULL         | A    |      1 |    340 |    340 |00:00:00.01 |       3 |      0 |
|*  4 |    INDEX RANGE SCAN          | HIX  |    340 |      1 |    200 |00:00:00.02 |      33 |      3 |
|   5 |   TABLE ACCESS BY INDEX ROWID| H    |    200 |      1 |    200 |00:00:00.01 |       4 |      1 |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("H"."OBJECT_ID"="A"."ID" AND "H"."LEVEL_ID"='Level1')
       filter(("H"."CLASS_ID"='class1' OR "H"."CLASS_ID"='class2'))

因此,请检查您的Oracle版本(我在12.1上)

验证统计信息是否正确。

检查系统统计信息。

检查您的Oracle CBO参数是否正常。