Oracle: значительно улучшить производительность запросов

У меня есть следующий запрос, для которого я пытаюсь улучшить производительность:

select atx.journal_id
    ,ab.c_date
from acct_batch ab 
    join acct_tx atx on ab.acct_id = atx.acct_id 
      and ab.batch_id = atx.batch_id
    join journal j on j.journal_id = atx.journal_id
      and j.journal_type_id = 6
    join acct a on a.acct_id = atx.acct_id 
      and a.acct_type_id = 32
    join payments p on p.payment_id = j.payment_id
    join routing r on r.route_id = p.route_id 
      and r.acq_code = 'RZ_NS'
    join acq_acct aa on aa.acq_code = r.acq_code
      and aa.acq_acct_code = r.acq_acct_code
      and aa.slc = 'MXM'
where ab.c_date between to_date(to_char('01-JUL-2015')) and  last_day(sysdate);

Я выполнил и рассмотрел план объяснения, и общая стоимость составляет 7388. Из этого самым дорогим является объединение с journal Стол, который имеет стоимость 6319.

Part_of_explain_plan

Таблица содержит приблизительно 1,6 миллиона строк с 87 разделами, из которых только две содержат строки (раздел 6 с 1,4 миллионами и раздел 12 с приблизительным остатком 200 тыс. Строк).

Первое, что я попробовал, это переписать запрос, чтобы избежать полного сканирования при сопоставлении фактического journal_type_id с 6, но я думаю, что мое понимание было неверным, потому что стоимость осталась 7388.

select atx.journal_id
    ,ab.c_date
from acct_batch ab 
    join acct_tx atx on ab.acct_id = atx.acct_id 
      and ab.batch_id = atx.batch_id
    join (select 
              journal_id
              , payment_id 
          from journal 
          where journal_type_id = 6) j on j.journal_id = atx.journal_id
    join acct a on a.acct_id = atx.acct_id 
      and a.acct_type_id = 32
    join payments p on p.payment_id = j.payment_id
    join routing r on r.route_id = p.route_id 
      and r.acq_code = 'RZ_NS'
    join acq_acct aa on aa.acq_code = r.acq_code
      and aa.acq_acct_code = r.acq_acct_code
      and aa.slc = 'MXM'
where ab.c_date between to_date(to_char('01-JUL-2015')) and  last_day(sysdate);

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

Я все еще активно ищу способы улучшить производительность, но я подумал, что я бы здесь написал вопрос, чтобы, возможно, получить некоторые подсказки.

Я думаю, что человек из видео говорит о том, что первое, что нужно сделать, - это определить, какой у вас "движущий стол" (тот, который определяет, какие строки выбираются - на основе ключа), поэтому я сейчас ищу для способа переписать запрос, чтобы идентифицировать и максимально использовать эту таблицу управления и ее индексы.

Я не знаю, нахожусь ли я на правильном пути, но, пожалуйста, остановите меня, если вы думаете, что я должен поступить иначе. Также, пожалуйста, обратите внимание, что я абсолютный новичок в настройке производительности, на самом деле это мой первый.

Любая помощь приветствуется.

Обновить:

Некоторые из индексов, которые содержат столбцы, используемые в запросах:

╔════════════╦═══════════════╦════════════╦═══════════╦═════════════╦═══════════════════════════════════╗
║   Table    ║   IndexName   ║ Uniqueness ║ IndexType ║ Partitioned ║              Columns              ║
╠════════════╬═══════════════╬════════════╬═══════════╬═════════════╬═══════════════════════════════════╣
║ Acct_Batch ║ Acct_Batch_PK ║ UNIQUE     ║ NORMAL    ║ NO          ║ Acct_ID, Batch_ID                 ║
║ Acct_TX    ║ Acct_TX_IDX   ║ NONUNIQUE  ║ NORMAL    ║ YES         ║ Acct_ID, Batch_ID                 ║
║ Acct_TX    ║ Acct_TX_BIDX  ║ NONUNIQUE  ║ NORMAL    ║ YES         ║ Journal_ID, Acct_ID               ║
║ Journal    ║ Journal_PK    ║ UNIQUE     ║ NORMAL    ║ YES         ║ Journal_ID                        ║
║ Journal    ║ JType_BIDX    ║ NONUNIQUE  ║ NORMAL    ║ YES         ║ Journal_Type_ID, Book_Date        ║
║ Journal    ║ JType_BIDX_2  ║ NONUNIQUE  ║ NORMAL    ║ YES         ║ MCODE, Journal_Type_ID, Book_Date ║
║ Journal    ║ JPay_BIDX     ║ NONUNIQUE  ║ NORMAL    ║ YES         ║ Payment_ID, Journal_ID            ║
╚════════════╩═══════════════╩════════════╩═══════════╩═════════════╩═══════════════════════════════════╝

Дайте мне знать, если вам нужно увидеть больше индексов или подробностей относительно других таблиц.

Примерный план объяснения:

-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                 | Name              | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |                   |     1 |   160 |  7388   (1)| 00:01:29 |       |       |
|*  1 |  FILTER                                   |                   |       |       |            |          |       |       |
|   2 |   NESTED LOOPS                            |                   |       |       |            |          |       |       |
|   3 |    NESTED LOOPS                           |                   |     1 |   160 |  7388   (1)| 00:01:29 |       |       |
|*  4 |     HASH JOIN                             |                   |     4 |   604 |  7380   (1)| 00:01:29 |       |       |
|   5 |      NESTED LOOPS                         |                   |       |       |            |          |       |       |
|   6 |       NESTED LOOPS                        |                   |   107 | 14338 |  7372   (1)| 00:01:29 |       |       |
|*  7 |        HASH JOIN                          |                   |    27 |  3186 |  7298   (1)| 00:01:28 |       |       |
|   8 |         NESTED LOOPS                      |                   |       |       |            |          |       |       |
|   9 |          NESTED LOOPS                     |                   |   102 | 10302 |   978   (0)| 00:00:12 |       |       |
|  10 |           NESTED LOOPS                    |                   |    11 |   638 |    37   (0)| 00:00:01 |       |       |
|* 11 |            TABLE ACCESS BY INDEX ROWID    | ACQ_ACCT          |    11 |   253 |     4   (0)| 00:00:01 |       |       |
|* 12 |             INDEX RANGE SCAN              | AA_PK             |    16 |       |     2   (0)| 00:00:01 |       |       |
|  13 |            TABLE ACCESS BY INDEX ROWID    | ROUTES            |     1 |    35 |     3   (0)| 00:00:01 |       |       |
|* 14 |             INDEX RANGE SCAN              | R_A_BIDX          |     1 |       |     2   (0)| 00:00:01 |       |       |
|  15 |           PARTITION RANGE ALL             |                   |    95 |       |    84   (0)| 00:00:02 |     1 |    84 |
|* 16 |            INDEX RANGE SCAN               | P_R_ID_BIDX       |    95 |       |    84   (0)| 00:00:02 |     1 |    84 |
|  17 |          TABLE ACCESS BY LOCAL INDEX ROWID| PAYMENTS          |     9 |   387 |   100   (0)| 00:00:02 |     1 |     1 |
|  18 |         PARTITION RANGE ALL               |                   |   107K|  1782K|  6319   (1)| 00:01:16 |     1 |    87 |
|* 19 |          TABLE ACCESS FULL                | JOURNAL           |   107K|  1782K|  6319   (1)| 00:01:16 |     1 |    87 |
|  20 |        PARTITION RANGE ITERATOR           |                   |     4 |       |     2   (0)| 00:00:01 |   KEY |   KEY |
|* 21 |         INDEX RANGE SCAN                  | ATX_A_IDX         |     4 |       |     2   (0)| 00:00:01 |   KEY |   KEY |
|  22 |       TABLE ACCESS BY LOCAL INDEX ROWID   | ACCT_TX           |     4 |    64 |     3   (0)| 00:00:01 |     1 |     1 |
|* 23 |      INDEX RANGE SCAN                     | AB_B_A_IDX        |  5006 | 85102 |     8   (0)| 00:00:01 |       |       |
|* 24 |     INDEX UNIQUE SCAN                     | ACC_PK            |     1 |       |     1   (0)| 00:00:01 |       |       |
|* 25 |    TABLE ACCESS BY INDEX ROWID            | ACCT              |     1 |     9 |     2   (0)| 00:00:01 |       |       |
-------------------------------------------------------------------------------------------------------------------------------

2 ответа

Решение

Таким образом, после более тщательного изучения кода данные отображаются на основе столбцов, перечисленных в SELECT В рамках запроса я заметил, что последняя присоединенная таблица не вносит никакого вклада (не требует отображения каких-либо данных из нее) в вывод.

join acq_acct aa on aa.acq_code = r.acq_code
  and aa.acq_acct_code = r.acq_acct_code
  and aa.slc = 'MXM'

Следовательно, я переместил этот запрос в EXISTS пункт и повторно запустил запрос. Мой измененный запрос выглядит так:

select atx.journal_id
    ,ab.c_date
from acct_batch ab 
    join acct_tx atx on ab.acct_id = atx.acct_id 
      and ab.batch_id = atx.batch_id
    join journal j on j.journal_id = atx.journal_id
      and j.journal_type_id = 6
    join acct a on a.acct_id = atx.acct_id 
      and a.acct_type_id = 32
    join payments p on p.payment_id = j.payment_id
    join routing r on r.route_id = p.route_id 
      and r.acq_code = 'RZ_NS'
where ab.c_date between to_date(to_char('01-JUL-2015')) and  last_day(sysdate)
    and exists (select 1
                from acq_acct aa
                where aa.acq_code = r.acq_code
                    and aa.acq_acct_code = r.acq_acct_code
                    and aa.slc = 'MXM');

Это помогло улучшить стоимость моего запроса с 7388 до 292, что является колоссальной разницей.

Надеюсь, я правильно понял это, и мое объяснение также имело смысл.

Если кто-то считает, что мои выводы были неверными или "логические рассуждения" были неверными, пожалуйста, оставьте комментарий (сейчас мои выводы / объяснения сверху имеют смысл для меня).

Сначала убедитесь, что ваша статистика обновляется: оптимизатор сильно зависит от статистики! Во-вторых, вы должны сказать что-то о количестве строк, которые вы получаете с помощью этого запроса: в зависимости от количества строк, которые выбирает каждое условие, может быть лучше полное сканирование, чем поиск по индексу.

Другие вопросы по тегам