Индексированный запрос Oracle SQL использует процессор на 100% - PullRequest
0 голосов
/ 30 апреля 2018

Я выполняю относительно простой запрос

SELECT * FROM confirm_v c
JOIN person p ON c.created_by=p.id
INNER JOIN invoice_confirm ic ON ic.confirm_id=c.id
WHERE c.id = (SELECT id FROM 
                 (SELECT c2.id FROM confirm c2
                  JOIN invoice_confirm ic2 ON ic2.confirm_id=c2.id
                  WHERE ic2.invoice_id=11954081
                  AND c2.previous=0
                  AND c2.canceled=0
                  AND c2.confirm_type='INVOICE'
                  ORDER BY c2.id)
              WHERE rownum=1);

, что приводит к 100% -ному использованию процессора rdb. confirm_type - это varchar2(50 char), остальные - number(10), если это что-то значит.

Таблицы invoice_confirm и confirm покрыты индексами, и в плане выполнения этого запроса нет видимых полных сканирований таблиц.

Этот запрос выполняется не часто, но на него приходится почти 100% общего использования ЦП. Любые идеи приветствуются.

EDIT: План объяснения в тексте из-за запроса.

EXPLAIN PLAN FOR ...
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
Plan hash value: 1705859247


------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                      | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                               |                             |     1 |    69 |    10   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                                  |                             |     1 |    69 |    10   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                                 |                             |     1 |    69 |    10   (0)| 00:00:01 |
|   3 |    NESTED LOOPS                                |                             |     1 |    57 |     7   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                               |                             |     1 |    30 |     5   (0)| 00:00:01 |
|   5 |      TABLE ACCESS BY INDEX ROWID               | CONFIRM                     |     1 |    24 |     3   (0)| 00:00:01 |
|*  6 |       INDEX UNIQUE SCAN                        | PK_CONFIRM                  |     1 |       |     2   (0)| 00:00:01 |
|*  7 |        COUNT STOPKEY                           |                             |       |       |            |          |
|   8 |         VIEW                                   |                             |     4 |    52 |    27   (4)| 00:00:01 |
|*  9 |          SORT ORDER BY STOPKEY                 |                             |     4 |   132 |    27   (4)| 00:00:01 |
|  10 |           NESTED LOOPS                         |                             |     4 |   132 |    26   (0)| 00:00:01 |
|  11 |            NESTED LOOPS                        |                             |    11 |   132 |    26   (0)| 00:00:01 |
|  12 |             TABLE ACCESS BY INDEX ROWID BATCHED| INVOICE_CONFIRM             |     3 |    36 |     4   (0)| 00:00:01 |
|* 13 |              INDEX RANGE SCAN                  | FKI_INVOICE_CONFIRM_INVOICE |     2 |       |     3   (0)| 00:00:01 |
|* 14 |             INDEX UNIQUE SCAN                  | PK_CONFIRM                  |     1 |       |     1   (0)| 00:00:01 |
|* 15 |            TABLE ACCESS BY INDEX ROWID         | CONFIRM                     |     1 |    21 |     2   (0)| 00:00:01 |
|* 16 |      INDEX RANGE SCAN                          | FKI_INVOICE_CONFIRM_CONFIRM |     1 |     6 |     2   (0)| 00:00:01 |
|  17 |     TABLE ACCESS BY INDEX ROWID                | PERSON                      |     1 |    27 |     2   (0)| 00:00:01 |
|* 18 |      INDEX UNIQUE SCAN                         | PK_KASUTAJA                 |     1 |       |     1   (0)| 00:00:01 |
|* 19 |    INDEX RANGE SCAN                            | FKI_INVOICE_CONFIRM_CONFIRM |     1 |       |     2   (0)| 00:00:01 |
|  20 |   TABLE ACCESS BY INDEX ROWID                  | INVOICE_CONFIRM             |     1 |    12 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------------------

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

   6 - access("CONFIRM"."ID"= (SELECT "ID" FROM  (SELECT "C2"."ID" "ID" FROM "INVOICE_CONFIRM" "IC2","CONFIRM" "C2" 
              WHERE "IC2"."CONFIRM_ID"="C2"."ID" AND "C2"."CANCELED"=0 AND "C2"."PREVIOUS"=0 AND "C2"."CONFIRM_TYPE"='INVOICE' AND 
              "IC2"."INVOICE_ID"=11954081 ORDER BY "C2"."ID") "from$_subquery$_006" WHERE ROWNUM=1))
   7 - filter(ROWNUM=1)
   9 - filter(ROWNUM=1)
  13 - access("IC2"."INVOICE_ID"=11954081)
  14 - access("IC2"."CONFIRM_ID"="C2"."ID")
  15 - filter("C2"."CANCELED"=0 AND "C2"."PREVIOUS"=0 AND "C2"."CONFIRM_TYPE"='INVOICE')
  16 - access("IC"."CONFIRM_ID"="CONFIRM"."ID")
  18 - access("CONFIRM"."CREATED_BY"="P"."ID")
  19 - access("IC"."CONFIRM_ID"="CONFIRM"."ID")

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - 2 Sql Plan Directives used for this statement

1 Ответ

0 голосов
/ 01 мая 2018

Соберите статистику оптимизатора по соответствующим таблицам и выясните, почему статистика отсутствовала.

begin
    dbms_stats.gather_table_stats(user, 'CONFIRM');
    dbms_stats.gather_table_stats(user, 'INVOICE_CONFIRM');
    dbms_stats.gather_table_stats(user, 'PERSON');
end;
/

Статистика оптимизатора имеет решающее значение для достижения высокой производительности Oracle. Примечание dynamic statistics used: dynamic sampling (level=2) подразумевает, что есть таблицы с отсутствующей статистикой оптимизатора. Этого никогда не должно произойти, если таблицы не были созданы в течение последнего дня.

Oracle автоматически собирает устаревшую и отсутствующую статистику. Проверьте, выполняется ли задание с этим запросом. Если последние строки отсутствуют, попросите своего администратора базы данных снова включить задачу.

select *
from dba_optstat_operations
where operation like '%auto%'
order by start_time desc;

Автозадача достаточно хороша для большинства таблиц. Но если есть большой пакетный процесс, который обновляет много строк, тогда статистику следует собирать вручную, как только задание будет завершено.

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