2015-04-12 5 views
3

У меня есть простой запрос, который работает навсегда. Существует одно условие даты, которое, как только я удаляю, запрос возвращается с результатами. Его поле даты в формате '31 -MAR-15 '. Я не понимаю, почему это условие делает запрос настолько медленным. Заранее спасибо.Oracle - запрос выполняется очень медленно

SELECT 
    substr(a.id, 1, 2) AS country, 
    count(DISTINCT a.id) AS id_count, 
    sum(a.amount)  AS amount 
FROM table1 a 
    JOIN table2 b ON a.id = b.id 
    JOIN table3 c ON b.party_id = c.party_id 
WHERE a.prod_type = 'INS' 
    AND c.acct_type = 'LON' 
    AND substr(a.id, 1, 2) = 'US' 
    AND a.dump_dt = '31-MAR-15' 
    AND substr(id, 4, 8) = '20150303' 
GROUP BY substr(a.id, 1, 2); 

Explain Plan:

PLAN_TABLE_OUTPUT 
Plan hash value: 255044277 

------------------------------------------------------------------------------------------------------------ 
| Id | Operation       | Name     | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT     |      |  1 | 121 | 125K (1)| 00:25:08 | 
| 1 | HASH GROUP BY     |      |  1 | 121 | 125K (1)| 00:25:08 | 
| 2 | VIEW       | VW_DAG_0    |  1 | 121 | 125K (1)| 00:25:08 | 
| 3 | HASH GROUP BY     |      |  1 | 98 | 125K (1)| 00:25:08 | 
| 4 |  NESTED LOOPS     |      |  |  |   |   | 
| 5 |  NESTED LOOPS     |      |  1 | 98 | 125K (1)| 00:25:08 | 
| 6 |  MERGE JOIN CARTESIAN  |      | 12613 | 800K| 21133 (2)| 00:04:14 | 
|* 7 |  TABLE ACCESS BY INDEX ROWID| TABLE1     |  1 | 45 | 46 (0)| 00:00:01 | 
|* 8 |   INDEX RANGE SCAN   | DATA_DATE__STG_BACKUP2 | 1040 |  |  6 (0)| 00:00:01 | 
| 9 |  BUFFER SORT    |      | 182K| 3564K| 21087 (2)| 00:04:14 | 
|* 10 |   TABLE ACCESS FULL   | TABLE3     | 182K| 3564K| 21087 (2)| 00:04:14 | 
|* 11 |  INDEX RANGE SCAN   | BSB_PARTYID_IDX  | 22 |  |  3 (0)| 00:00:01 | 
|* 12 |  TABLE ACCESS BY INDEX ROWID | TABLE2     |  1 | 33 | 10 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------------------ 

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

    7-filter(SUBSTR(A.ID, 4, 8) = '20150303' AND SUBSTR(A.ID, 1, 2) = 'US' 
       AND A.PROD_TYPE = 'INS') 
    8 - access(A.DUMP_DT = '31-MAR-15') 
    10 - filter(C.ACCT_TYPE = 'LON') 
    11 – access(B.PARTY_ID = C.PARTY_ID) 
    12 - filter(A.ID = B.ID) 
+1

Что тип 'dump_dt'? Какие индексы у вас есть? Каков план объяснений? – Mat

+0

Вы проверили, что есть индекс на DUMP_DT? – PhillipD

+2

Это недопустимый SQL для Oracle, который не поддерживает ключевое слово 'AS' для таблиц псевдонимов. Есть что-то, о чем вы нам не говорите ... Поскольку другие указали таблицу DDL и объяснили, что планы являются _essential_, чтобы вы могли получить хороший ответ, кажется, что вы сохраняете даты как строки, которые всегда являются рецептом для катастрофа и, наконец, 'SUBSTR (ID, 4, 9)' возвращает 9 символов, а не 8, поэтому, если идентификатор меньше 13 символов, я ожидаю, что 'SUBSTR (ID, 4, 9) = '20150303'' всегда будет возвращаться ничего, что означает, что ваш запрос ничего не возвращает. Не могли бы вы прояснить свой вопрос? – Ben

ответ

1

Похоже, оптимизатор значительно недооценки количество возвращаемых строк после применения этих 4 предиката на TABLE1.

A.PROD_TYPE = 'INS' 
SUBSTR(A.ID, 1, 2) = 'US' 
A.DUMP_DT = '31-MAR-15' 
SUBSTR(ID, 4, 8) = '20150303' 

(Немного не по теме: это безопаснее использовать ANSI буквального date '2015-03-31' вместо неявно преобразуются строка '31-MAR-15' И оператор имеет несколько ошибок, как отсутствует условие между первыми 2 предикатами и недостающим. A. перед последним предиката)

во-первых, убедитесь, что есть точные статистические данные по всем таблицам и посмотреть, если это изменяет объяснить план:.

begin 
    dbms_stats.gather_table_stats(user, 'TABLE1'); 
    dbms_stats.gather_table_stats(user, 'TABLE2'); 
    dbms_stats.gather_table_stats(user, 'TABLE3'); 
end; 
/

в «СМА rt column ", ID, затрудняет оценку количества строк, возвращаемых после применения условий. Если это слишком поздно, чтобы изменить модель данных, вы можете по крайней мере, предоставить Oracle с некоторой расширенной статистикой, чтобы помочь ему справиться с предикатами:

select dbms_stats.create_extended_stats(user, 'TABLE1', '(SUBSTR(ID, 1, 2))') from dual; 
select dbms_stats.create_extended_stats(user, 'TABLE1', '(SUBSTR(ID, 4, 8))') from dual; 

Я предполагаю, что SUBSTR(A.ID, 1, 2) = 'US' является популярным значением, но без расширенной статистики Oracle этого не узнает. Дополнительная гистограмма может значительно увеличить мощность. Тогда оптимизатор не будет выбирать декартово соединение между двумя несвязанными таблицами.

-1

Попробуйте использовать оракул подсказки для стабилизации плана выбора или вы можете использовать этот трюк:

.... 
And A.DUMP_DT+0 = to_date('31-MAR-15','dd-mon- rr') 
... 
1

я упростил условия в ИНЕКЕ над A.ID поле

A.ID LIKE 'US_20150303%' 

имеет тот же эффект, что и

substr(a.id, 1, 2) = 'US' AND substr(id, 4, 8) = '20150303' 

и, в случае столбец A.ID был проиндексирован, факт применения SUBSTR (a.ID, ..) Функция делает индекс бесполезным.

С другой стороны, a.dump_dt кажется столбец типа DATE, поэтому предпочтительный способ применить фильтр на этой колонке может быть

a.dump_dt = TO_DATE('31-MAR-15', 'DD-MON-RR') 

вместо

a.dump_dt = '31-MAR-15' 

Последнее зависит в первую очередь от NLS_DATE_FORMAT клиента Oracle, выполняющего запрос, и в некоторых случаях может негативно повлиять на производительность, игнорируя использование индекса за a.dump_dt.

Так переписано запрос выглядит следующим образом:

SELECT 
    SUBSTR(A.ID, 1, 2) AS country, 
    COUNT(DISTINCT A.ID) AS id_count, 
    SUM(A.amount)  AS amount 
FROM table1 A 
    JOIN table2 b ON A.ID = b.ID 
    JOIN table3 c ON b.party_id = c.party_id 
WHERE A.prod_type = 'INS' 
    AND c.acct_type = 'LON' 
    AND A.ID LIKE 'US_20150303%' 
    AND A.dump_dt = TO_DATE('31-MAR-15', 'DD-MON-RR') 
GROUP BY SUBSTR(A.ID, 1, 2); 
+0

Привет, вы можете отредактировать свой ответ, чтобы объяснить, что делает этот запрос и как он исправляет проблему? Кодовые ответы не поощряются и могут быть удалены. Благодарю. –

Смежные вопросы