Оптимизация запросов - выберите в левом соединении - PullRequest
0 голосов
/ 05 августа 2020

Я работаю над оптимизацией запроса sql и обнаружил конкретную строку, которая, похоже, снижает производительность моих запросов:

LEFT JOIN anothertable lastweek
AND lastweek.date>= (SELECT MAX(table.date)-7 max_date_lweek 
                                 FROM table table
                                 WHERE table.id= lastweek.id) 
AND lastweek.date< (SELECT MAX(table.date) max_date_lweek 
                                 FROM table table  
                                 WHERE table.id= lastweek.id) 

Я работаю над способом оптимизации этих строк , но я в тупике. Если у кого-то есть идеи, дайте мне знать!

-----------------------------------------------------------------------------------------------------------
| Id   | Operation                         | Name            | Rows      | Bytes      | Cost   | Time     |
-----------------------------------------------------------------------------------------------------------
|    0 | SELECT STATEMENT                  |                 |   1908654 |  145057704 | 720461 | 00:00:29 |
|  * 1 |   HASH JOIN RIGHT OUTER           |                 |   1908654 |  145057704 | 720461 | 00:00:29 |
|    2 |    VIEW                           | VW_DCL_880D8DA3 |    427487 |    7694766 | 716616 | 00:00:28 |
|  * 3 |     HASH JOIN                     |                 |    427487 |   39328804 | 716616 | 00:00:28 |
|    4 |      VIEW                         | VW_SQ_2         |   7174144 |  193701888 | 278845 | 00:00:11 |
|    5 |       HASH GROUP BY               |                 |   7174144 |  294139904 | 278845 | 00:00:11 |
|    6 |        TABLE ACCESS STORAGE FULL  | TASK            | 170994691 | 7010782331 |  65987 | 00:00:03 |
|  * 7 |      HASH JOIN                    |                 |   8549735 |  555732775 | 429294 | 00:00:17 |
|    8 |       VIEW                        | VW_SQ_1         |   7174144 |  172179456 | 278845 | 00:00:11 |
|    9 |        HASH GROUP BY              |                 |   7174144 |  294139904 | 278845 | 00:00:11 |
|   10 |         TABLE ACCESS STORAGE FULL | TASK            | 170994691 | 7010782331 |  65987 | 00:00:03 |
|   11 |       TABLE ACCESS STORAGE FULL   | TASK            | 170994691 | 7010782331 |  65987 | 00:00:03 |
| * 12 |    TABLE ACCESS STORAGE FULL      | TASK            |   1908654 |  110701932 |   2520 | 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("SYS_ID"(+)="TASK"."PARENT")
* 3 - access("ITEM_2"="TASK_LWEEK"."SYS_ID")
* 3 - filter("TASK_LWEEK"."SNAPSHOT_DATE"<"MAX_DATE_LWEEK")
* 7 - access("ITEM_1"="TASK_LWEEK"."SYS_ID")
* 7 - filter("TASK_LWEEK"."SNAPSHOT_DATE">=INTERNAL_FUNCTION("MAX_DATE_LWEEK"))
* 12 - storage("TASK"."CLOSED_AT" IS NULL OR "TASK"."CLOSED_AT">=TRUNC(SYSDATE@!)-15)
* 12 - filter("TASK"."CLOSED_AT" IS NULL OR "TASK"."CLOSED_AT">=TRUNC(SYSDATE@!)-15)

Ответы [ 3 ]

1 голос
/ 05 августа 2020

Ну ты даже не показываешь select. Как я вижу, выбор выполняется через Exadata (Table Access Storage Full), возможно, вам нужно спросить себя, зачем вам нужно делать 4 доступа к одной и той же таблице.

Вы получаете доступ четвертый раз (строки 6 , 10, 11, 12) в основную таблицу TASK с 170994691 строками (на основе оценки CBO). Я не знаю, актуальна ли статистика или она оптимизирует выборку из-за отсутствия хорошей статистики. ваш проектный запрос

with my_set as 
 (SELECT MAX(table.date)-7 max_date_lweek  , 
         max(table.date) as max_date, 
         id from FROM table ) 
select 
.......................
from ...
left join anothertable lastweek on ( ........ ) 
left join myset on ( anothertable.id = myset.id ) 
where 
      lastweek.date >= myset.max_date_lweek  
      and 
      lastweek.date < myset.max_date

Пожалуйста, примите во внимание, что вы не предоставили запрос, поэтому я предполагаю многое.

0 голосов
/ 05 августа 2020

Если посмотреть на ваш план объяснения, доступ к таблице будет только TASK. Из этого я делаю вывод, что таблицы в вашем примере: ANOTHERTABLE и TABLE на самом деле являются одной и той же таблицей, и поэтому вы пытаетесь получить данные за последнюю неделю, которые существуют в этой таблице для каждого значения id. .

Если все это правда, будет намного быстрее использовать функцию analyti c для получения максимального значения даты для каждого id, а затем ограничения на основе этого.

Вот пример того, что я имею в виду. Обратите внимание: я использую «dte» вместо «date», чтобы избежать путаницы с зарезервированным словом «date».

LEFT JOIN ( SELECT lastweek.*, 
                   max(dte) OVER ( PARTITION BY id ) max_date 
            FROM   anothertable lastweek ) lastweek
ON 1=1  -- whatever other join conditions you have, seemingly omitted from your post
AND lastweek.dte >= lastweek.max_date - 7;

Опять же, это работает, только если я правильно считаю, что table и anothertable фактически одна и та же таблица.

0 голосов
/ 05 августа 2020

Поскольку полная информация недоступна, я предлагаю:

Вы используете один и тот же запрос дважды, тогда почему бы не использовать CTE, например

with CTE_example as (SELECT MAX(table.date), max_date_lweek, ID 
                                 FROM table table)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...