План странного выполнения с Oracle Invisible Index - PullRequest
1 голос
/ 07 апреля 2019

Мой вопрос о странном плане выполнения, который я вижу при работе с индексами INVISIBLE. База данных 11g

Для тестирования производительности конкретного запроса были созданы два невидимых индекса.

Когда я выполняю этот запрос без каких-либо подсказок и параметра OPTIMIZER_USE_INVISIBLE_INDEXES = FALSE, запрос выполняет ожидаемое полное сканирование таблицы и возвращает строки за 148 секунд со степенью параллелизма 21 (запрос № 1 ниже)

Когда я выполняю этот запрос с подсказкой / * + USE_INVISIBLE_INDEXES * / и параметром OPTIMIZER_USE_INVISIBLE_INDEXES = TRUE, запрос выполняет INDEX FAST FULL SCAN и возвращает строки за 122 секунды со степенью параллелизма 26 (запрос № 2 ниже)

Когда я выполняю этот запрос, называя индексы с именем hint / * + INDEX * / и параметром OPTIMIZER_USE_INVISIBLE_INDEXES = TRUE, запрос выполняет INDEX FULL SCAN и INDEX RANGE SCAN и занимает максимальное время 649 секунд со степенью параллелизм 13 (запрос № 3 ниже)

Тенденция d.o.p, а также план и время выполнения остаются неизменными в зависимости от порядка выполнения запросов.

Интересно, может кто-нибудь объяснить, почему присвоение имен индексам приводит к самым высоким затратам и времени возврата? Если мне нужно использовать индексы, я должен назвать это. Использование подсказки / * + USE_INVISIBLE_INDEXES * / невозможно после продвижения кода.

Индексы:

CREATE INDEX INVOICELINE_IDX_PRF2
ON INVOICELINE (invoiceheaderid, chargetypeid, agreementid, unpaidamount)
INVISIBLE COMPUTE STATISTICS ;

CREATE INDEX INVOICEHEADER_IDX_PRF0
ON INVOICEHEADER (id, TRUNC(invoiceduedate))
INVISIBLE COMPUTE STATISTICS ;

С подсказкой: подсказка не используется; Полное сканирование таблицы

Время вывода: 148 с

Запрос № 1:

    WITH V1
    AS 
    (
        SELECT 
             T1.agreementid             AS  agrmnt_id
            ,T1.invoicelineamount       AS  invc_line_amt
            ,TRUNC(T2.invoiceduedate)   AS  invc_due_dt
            ,T1.unpaidamount            AS  unpaid_amt
            ,T3.groupname               AS  grp_nm
        FROM
             INVOICELINE        T1
            ,INVOICEHEADER      T2
            ,CHARGETYPE         T3
        WHERE 1=1
          AND T2.id = T1.invoiceheaderid
          AND T3.id = T1.chargetypeid
    )
    SELECT /*+ PARALLEL(AUTO) */
        agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
    FROM
        V1
    WHERE 1=1
      AND UPPER(grp_nm)='INSTALMENT'
    GROUP BY
        agrmnt_id, invc_due_dt
    ;

План выполнения:

----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                  |       |       |       |  6329 (100)|          |        |      |            |
|   1 |  PX COORDINATOR                            |                  |       |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)                      | :TQ10003         |  1381K|    55M|       |  6329   (6)| 00:00:01 |  Q1,03 | P->S | QC (RAND)  |
|   3 |    HASH GROUP BY                           |                  |  1381K|    55M|    68M|  6329   (6)| 00:00:01 |  Q1,03 | PCWP |            |
|   4 |     PX RECEIVE                             |                  |  1381K|    55M|       |  6329   (6)| 00:00:01 |  Q1,03 | PCWP |            |
|   5 |      PX SEND HASH                          | :TQ10002         |  1381K|    55M|       |  6329   (6)| 00:00:01 |  Q1,02 | P->P | HASH       |
|   6 |       HASH GROUP BY                        |                  |  1381K|    55M|    68M|  6329   (6)| 00:00:01 |  Q1,02 | PCWP |            |
|*  7 |        HASH JOIN                           |                  |  1381K|    55M|       |  5804   (6)| 00:00:01 |  Q1,02 | PCWP |            |
|   8 |         PX RECEIVE                         |                  |  1381K|    35M|       |  3928   (7)| 00:00:01 |  Q1,02 | PCWP |            |
|   9 |          PX SEND BROADCAST                 | :TQ10001         |  1381K|    35M|       |  3928   (7)| 00:00:01 |  Q1,01 | P->P | BROADCAST  |
|  10 |           VIEW                             | VW_GBC_13        |  1381K|    35M|       |  3928   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  11 |            HASH GROUP BY                   |                  |  1381K|    63M|    79M|  3928   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  12 |             PX RECEIVE                     |                  |  1381K|    63M|       |  3928   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  13 |              PX SEND HASH                  | :TQ10000         |  1381K|    63M|       |  3928   (7)| 00:00:01 |  Q1,00 | P->P | HASH       |
|  14 |               HASH GROUP BY                |                  |  1381K|    63M|    79M|  3928   (7)| 00:00:01 |  Q1,00 | PCWP |            |
|* 15 |                HASH JOIN                   |                  |  1381K|    63M|       |  3348   (8)| 00:00:01 |  Q1,00 | PCWP |            |
|  16 |                 JOIN FILTER CREATE         | :BF0000          |     6 |   162 |       |     2   (0)| 00:00:01 |  Q1,00 | PCWP |            |
|* 17 |                  TABLE ACCESS STORAGE FULL | CHARGETYPE       |     6 |   162 |       |     2   (0)| 00:00:01 |  Q1,00 | PCWP |            |
|  18 |                 JOIN FILTER USE            | :BF0000          |   138M|  2766M|       |  3324   (7)| 00:00:01 |  Q1,00 | PCWP |            |
|  19 |                  PX BLOCK ITERATOR         |                  |   138M|  2766M|       |  3324   (7)| 00:00:01 |  Q1,00 | PCWC |            |
|* 20 |                   TABLE ACCESS STORAGE FULL| INVOICELINE      |   138M|  2766M|       |  3324   (7)| 00:00:01 |  Q1,00 | PCWP |            |
|  21 |         PX BLOCK ITERATOR                  |                  |   129M|  1857M|       |  1855   (2)| 00:00:01 |  Q1,02 | PCWC |            |
|* 22 |          TABLE ACCESS STORAGE FULL         | INVOICEHEADER    |   129M|  1857M|       |  1855   (2)| 00:00:01 |  Q1,02 | PCWP |            |
----------------------------------------------------------------------------------------------------------------------------------------------------

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

    7 - access(T2.ID=ITEM_1)
    15 - access(T3.ID=T1.CHARGETYPEID)
    17 - storage(UPPER(T3.GROUPNAME)=U'INSTALMENT')
       filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
    20 - storage(:Z>=:Z AND :Z<=:Z AND SYS_OP_BLOOM_FILTER(:BF0000,T1.CHARGETYPEID))
       filter(SYS_OP_BLOOM_FILTER(:BF0000,T1.CHARGETYPEID))
    22 - storage(:Z>=:Z AND :Z<=:Z)

Note
-----
   - dynamic statistics used: dynamic sampling (level=AUTO)
   - automatic DOP: Computed Degree of Parallelism is 21

С подсказкой: / * + USE_INVISIBLE_INDEXES * /

Время вывода: 122 с

Запрос № 2:

    WITH V1
    AS 
    (
        SELECT /*+ USE_INVISIBLE_INDEXES */
             T1.agreementid             AS  agrmnt_id
            ,T1.invoicelineamount       AS  invc_line_amt
            ,TRUNC(T2.invoiceduedate)   AS  invc_due_dt
            ,T1.unpaidamount            AS  unpaid_amt
            ,T3.groupname               AS  grp_nm
        FROM
             INVOICELINE        T1
            ,INVOICEHEADER      T2
            ,CHARGETYPE         T3
        WHERE 1=1
          AND T2.id = T1.invoiceheaderid
          AND T3.id = T1.chargetypeid
    )
    SELECT /*+ PARALLEL(AUTO) */
        agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
    FROM
        V1
    WHERE 1=1
      AND UPPER(grp_nm)='INSTALMENT'
    GROUP BY
        agrmnt_id, invc_due_dt
    ;

План выполнения:

---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name                      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |                           |       |       |       |  1505 (100)|          |        |      |            |
|   1 |  PX COORDINATOR                              |                           |       |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)                        | :TQ10003                  |  1381K|    55M|       |  1505   (7)| 00:00:01 |  Q1,03 | P->S | QC (RAND)  |
|   3 |    HASH GROUP BY                             |                           |  1381K|    55M|    68M|  1505   (7)| 00:00:01 |  Q1,03 | PCWP |            |
|   4 |     PX RECEIVE                               |                           |  1381K|    55M|       |  1505   (7)| 00:00:01 |  Q1,03 | PCWP |            |
|   5 |      PX SEND HASH                            | :TQ10002                  |  1381K|    55M|       |  1505   (7)| 00:00:01 |  Q1,02 | P->P | HASH       |
|   6 |       HASH GROUP BY                          |                           |  1381K|    55M|    68M|  1505   (7)| 00:00:01 |  Q1,02 | PCWP |            |
|*  7 |        HASH JOIN                             |                           |  1381K|    55M|       |  1082   (9)| 00:00:01 |  Q1,02 | PCWP |            |
|   8 |         PX RECEIVE                           |                           |  1381K|    35M|       |   815   (7)| 00:00:01 |  Q1,02 | PCWP |            |
|   9 |          PX SEND BROADCAST                   | :TQ10001                  |  1381K|    35M|       |   815   (7)| 00:00:01 |  Q1,01 | P->P | BROADCAST  |
|  10 |           VIEW                               | VW_GBC_13                 |  1381K|    35M|       |   815   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  11 |            HASH GROUP BY                     |                           |  1381K|    63M|    79M|   815   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  12 |             PX RECEIVE                       |                           |  1381K|    63M|       |   815   (7)| 00:00:01 |  Q1,01 | PCWP |            |
|  13 |              PX SEND HASH                    | :TQ10000                  |  1381K|    63M|       |   815   (7)| 00:00:01 |  Q1,00 | P->P | HASH       |
|  14 |               HASH GROUP BY                  |                           |  1381K|    63M|    79M|   815   (7)| 00:00:01 |  Q1,00 | PCWP |            |
|* 15 |                HASH JOIN                     |                           |  1381K|    63M|       |   346  (15)| 00:00:01 |  Q1,00 | PCWP |            |
|* 16 |                 TABLE ACCESS STORAGE FULL    | CHARGETYPE                |     6 |   162 |       |     2   (0)| 00:00:01 |  Q1,00 | PCWP |            |
|  17 |                 PX BLOCK ITERATOR            |                           |   138M|  2766M|       |   326  (10)| 00:00:01 |  Q1,00 | PCWC |            |
|* 18 |                  INDEX STORAGE FAST FULL SCAN| INVOICELINE_IDX_PRF2      |   138M|  2766M|       |   326  (10)| 00:00:01 |  Q1,00 | PCWP |            |
|  19 |         PX BLOCK ITERATOR                    |                           |   129M|  1857M|       |   250  (11)| 00:00:01 |  Q1,02 | PCWC |            |
|* 20 |          INDEX STORAGE FAST FULL SCAN        | INVOICEHEADER_IDX_PRF0    |   129M|  1857M|       |   250  (11)| 00:00:01 |  Q1,02 | PCWP |            |
---------------------------------------------------------------------------------------------------------------------------------------------------------------

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

    7 - access(T2.ID=ITEM_1)
    15 - access(T3.ID=T1.CHARGETYPEID)
    16 - storage(UPPER(T3.GROUPNAME)=U'INSTALMENT')
       filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
    18 - storage(:Z>=:Z AND :Z<=:Z)
    20 - storage(:Z>=:Z AND :Z<=:Z)

Note
-----
   - dynamic statistics used: dynamic sampling (level=AUTO)
   - automatic DOP: Computed Degree of Parallelism is 26

С подсказкой: / * + INDEX (T1 INVOICELINE_IDX_PRF2) INDEX (T2 INVOICEHEADER_IDX_PRF0) * /

Время вывода: 649 с

Запрос № 3:

    WITH V1
    AS 
    (
        SELECT /*+ INDEX(T1 INVOICELINE_IDX_PRF2) INDEX(T2 INVOICEHEADER_IDX_PRF0) */
             T1.agreementid             AS  agrmnt_id
            ,T1.invoicelineamount       AS  invc_line_amt
            ,TRUNC(T2.invoiceduedate)   AS  invc_due_dt
            ,T1.unpaidamount            AS  unpaid_amt
            ,T3.groupname               AS  grp_nm
        FROM
             INVOICELINE        T1
            ,INVOICEHEADER      T2
            ,CHARGETYPE         T3
        WHERE 1=1
          AND T2.id = T1.invoiceheaderid
          AND T3.id = T1.chargetypeid
    )
    SELECT /*+ PARALLEL(AUTO) */
        agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
    FROM
        V1
    WHERE 1=1
      AND UPPER(grp_nm)='INSTALMENT'
    GROUP BY
        agrmnt_id, invc_due_dt
    ;

План выполнения:

----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name                      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |                           |       |       |       |   658K(100)|          |        |      |            |
|   1 |  PX COORDINATOR                         |                           |       |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)                   | :TQ10002                  |  1381K|    55M|       |   658K  (1)| 00:00:26 |  Q1,02 | P->S | QC (RAND)  |
|   3 |    HASH GROUP BY                        |                           |  1381K|    55M|    68M|   658K  (1)| 00:00:26 |  Q1,02 | PCWP |            |
|   4 |     PX RECEIVE                          |                           |  1381K|    55M|       |   658K  (1)| 00:00:26 |  Q1,02 | PCWP |            |
|   5 |      PX SEND HASH                       | :TQ10001                  |  1381K|    55M|       |   658K  (1)| 00:00:26 |  Q1,01 | P->P | HASH       |
|   6 |       HASH GROUP BY                     |                           |  1381K|    55M|    68M|   658K  (1)| 00:00:26 |  Q1,01 | PCWP |            |
|   7 |        NESTED LOOPS                     |                           |  1381K|    55M|       |   657K  (1)| 00:00:26 |  Q1,01 | PCWP |            |
|   8 |         VIEW                            | VW_GBC_11                 |  1381K|    35M|       |   302K  (1)| 00:00:12 |  Q1,01 | PCWP |            |
|   9 |          HASH GROUP BY                  |                           |  1381K|    63M|    79M|   302K  (1)| 00:00:12 |  Q1,01 | PCWP |            |
|  10 |           PX RECEIVE                    |                           |  1381K|    63M|       |   302K  (1)| 00:00:12 |  Q1,01 | PCWP |            |
|  11 |            PX SEND HASH                 | :TQ10000                  |  1381K|    63M|       |   302K  (1)| 00:00:12 |  Q1,00 | P->P | HASH       |
|  12 |             HASH GROUP BY               |                           |  1381K|    63M|    79M|   302K  (1)| 00:00:12 |  Q1,00 | PCWP |            |
|  13 |              NESTED LOOPS               |                           |  1381K|    63M|       |   301K  (1)| 00:00:12 |  Q1,00 | PCWP |            |
|  14 |               PX BLOCK ITERATOR         |                           |       |       |       |            |          |  Q1,00 | PCWC |            |
|* 15 |                TABLE ACCESS STORAGE FULL| CHARGETYPE                |     6 |   162 |       |     2   (0)| 00:00:01 |  Q1,00 | PCWP |            |
|* 16 |               INDEX FULL SCAN           | INVOICELINE_IDX_PRF2      |   222K|  4569K|       | 50330   (1)| 00:00:02 |  Q1,00 | PCWP |            |
|* 17 |         INDEX RANGE SCAN                | INVOICEHEADER_IDX_PRF0    |     1 |    15 |       |     0   (0)|          |  Q1,01 | PCWP |            |
----------------------------------------------------------------------------------------------------------------------------------------------------------

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

    15 - storage(:Z>=:Z AND :Z<=:Z AND UPPER(T3.GROUPNAME)=U'INSTALMENT')
       filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
    16 - access(T3.ID=T1.CHARGETYPEID)
       filter(T3.ID=T1.CHARGETYPEID)
    17 - access(T2.ID=ITEM_1)

Note
-----
   - dynamic statistics used: dynamic sampling (level=AUTO)
   - automatic DOP: Computed Degree of Parallelism is 13

РЕДАКТИРОВАТЬ * * тысяча пятьдесят-одна Таблица насчитывает SAMPLE_SIZE LAST_ANALYZED INVOICELINE Count = 138,145,934 71258201 04-JUN-18 INVOICEHEADER Count = 129,865,795 133224960 02-APR-19 CHARGETYPE Count = 620 597 15-JUN-18

1 Ответ

0 голосов
/ 09 апреля 2019

Хммм ... Не могу сказать, что удивлен. Основываясь на количестве строк таблицы, размере выборки и последней проанализированной информации, я бы сказал, что лучше всего было бы как минимум проанализировать таблицы INVOICELINE и CHARGETYPE, как в

BEGIN
  DBMS_STATS.GATHER_TABLE_STATS('owner', 'INVOICEHEADER');
  DBMS_STATS.GATHER_TABLE_STATS('owner', 'INVOICELINE');
  DBMS_STATS.GATHER_TABLE_STATS('owner', 'CHARGETYPE');
END;

Измените 'владельца' выше на правильного владельца таблицы.

CHARGETYPE - довольно маленький столик, и, вероятно, он мало на что влияет, но не повредит. С другой стороны, счет-фактура почти удвоился с момента последнего анализа - и этот анализ был проведен более девяти месяцев назад, поэтому эти статистические данные, вероятно, очень устарели. Попробуйте.

Каждый раз, когда я вижу странные вещи, происходящие в плане, мой первый вопрос всегда звучит так: «Насколько хороши статистические данные в таблицах?». Сбор статистики довольно безопасен и вряд ли будет иметь какие-либо негативные последствия, за исключением времени, которое требуется для выполнения этих процедур, так что это, как правило, хорошая первая точка атаки для такой проблемы.

Удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...