В запросе не используется составной индекс - почему? - PullRequest
0 голосов
/ 28 декабря 2018

У меня есть запрос

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 - около 1 миллиарда записей.Запрос результата возвращает около 200 строк

Хотя все столбцы из индекса для таблицы h используются в условии соединения, в плане нет предиката доступа на уровне столбцов и class_id.Я не понимаю это решение.

Я хочу, чтобы уровень доступа был как минимум h.leate.Есть ли какие-то решения для этого?Или какой-то запрос переписать?

1 Ответ

0 голосов
/ 31 декабря 2018

Исходя из утверждения, что в результате запроса есть только 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.

...