Grzegorz D. PL/SQL Developer
Temat: [Oracle 10g] Optymalizacja zapytania z "OR"
Witajcie.Sprawa przedstawia się następująco - jedno z zapytań wykonuje mi się za długo, i muszę je jakoś zoptymalizować. To zapytanie nie zostało napisane przeze mnie, dlatego za wszystkie sugestie co do poprawności/szybkości konkretnych części będę bardzo wdzięczny.
Nie będę na razie wklejać zapytania, tylko postaram się opisać problem.
Moje zapytanie odpytuje perspektywę. Ta perspektywa odpytuje kolejną perspektywę, która korzysta z kilku tabelek. Jedna z nich jest dosyć duża (ok 20 mln wierszy) - ma wszystkie potrzebne indeksy i została spartycjonowana po polu z pewną datą (data_we). Czyli :
moje zapytanie
|
|
perspektywa 2 (kilka obliczeń)
|
|
perspektywa 1 (kilka operacji czyszczących)
|
|
Tabela_historyczna (joiny z mniejszymi tabelkami,partycje na data_we)
Gdybym ja to robił od początku - pewnie zbudowałbym to inaczej, jednak jest jak jest i raczej rzeczy z tych perspektyw, jak i samej struktury ruszać nie mogę.
Dochodząc do meritum, w zapytaniu znajduje się następujący warunek :
where
data_we between data1 and data2
or
(data_wy between data1 and data2 and data_we < data2).
W jaki sposób można to usprawnić? Dla pierwszego warunku przeglądam odpowiednie partycje - dla drugiego - przeglądam zdecydowaną większość partycji. Czy da się coś z tym zrobić?
Próbowałem rozbić ten warunek na dwa niezależne selecty połączone unionem, ale zapytanie działało jeszcze dłużej.
Zauważyłem, że gdy pojawi się taki warunek - szybciej działa przejrzenie całej tabeli nie uwzględniając partycji. Może przeglądając plan wykonania zapytania trochę więcej będziecie potrafili pomóc :
SELECT STATEMENT, GOAL = ALL_ROWS 156 1 124
SORT GROUP BY 1 124
PX COORDINATOR
PX SEND QC (RANDOM) SYS :TQ10006
BUFFER SORT 1 124
CONCATENATION
NESTED LOOPS OUTER 147 1 124
HASH JOIN OUTER 147 1 120
PX RECEIVE 141 1 104
PX SEND HASH SYS :TQ10002 141 1 104
BUFFER SORT 1 124
PX PARTITION RANGE ITERATOR 141 1 104
TABLE ACCESS BY LOCAL INDEX ROWID ATOSTEST NEW_HIST_MAIN_GD 141 1 104
INDEX RANGE SCAN ATOSTEST HIS_L_INDEX_GD 58 4149
PX RECEIVE 5 17099 273584
PX SEND HASH SYS :TQ10003 5 17099 273584
BUFFER SORT 1 124
VIEW SYS 5 17099 273584
HASH JOIN RIGHT OUTER 5 17099 923346
PX RECEIVE 2 93 1581
PX SEND BROADCAST SYS :TQ10000 2 93 1581
BUFFER SORT 1 124
VIEW SYS 2 93 1581
NESTED LOOPS 2 93 2232
PX BLOCK ITERATOR
TABLE ACCESS FULL CMM_DB CMM_EQP_TYPE_REVISION 2 93 1860
INDEX UNIQUE SCAN CMM_DB CMM_VENDOR_PK 0 1 4
PX BLOCK ITERATOR 3 17099 632663
TABLE ACCESS FULL NEW_CONFIG_DB EQP_NAME 3 17099 632663
INDEX UNIQUE SCAN NEW_CONFIG_DB PROBABLE_CAUSE_PK 0 1 4
NESTED LOOPS OUTER 10 1 124
HASH JOIN OUTER 10 1 120
PX RECEIVE 4 1 104
PX SEND HASH SYS :TQ10004 4 1 104
BUFFER SORT 1 124
PX PARTITION RANGE ITERATOR 4 1 104
TABLE ACCESS BY LOCAL INDEX ROWID ATOSTEST NEW_HIST_MAIN_GD 4 1 104
INDEX RANGE SCAN ATOSTEST HIS_DATETIME_UP_INDEX2_GD 1 89
PX RECEIVE 5 17099 273584
PX SEND HASH SYS :TQ10005 5 17099 273584
BUFFER SORT 1 124
VIEW SYS 5 17099 273584
HASH JOIN RIGHT OUTER 5 17099 923346
PX RECEIVE 2 93 1581
PX SEND BROADCAST SYS :TQ10001 2 93 1581
BUFFER SORT 1 124
VIEW SYS 2 93 1581
NESTED LOOPS 2 93 2232
PX BLOCK ITERATOR
TABLE ACCESS FULL CMM_DB CMM_EQP_TYPE_REVISION 2 93 1860
INDEX UNIQUE SCAN CMM_DB CMM_VENDOR_PK 0 1 4
PX BLOCK ITERATOR 3 17099 632663
TABLE ACCESS FULL NEW_CONFIG_DB EQP_NAME 3 17099 632663
INDEX UNIQUE SCAN NEW_CONFIG_DB PROBABLE_CAUSE_PK 0 1 4
Wrzucę jednak trochę więcej informacji :
Perspektywa 1 (NEW_HIST_MAIN_gd - największa tabela):
CREATE OR REPLACE VIEW HISTORY_DB.VW_ALARM_MAIN_2 AS
SELECT /*PARALLEL(ALARM) */
--jakies normalne kolumny
FROM atostest.NEW_HIST_MAIN_gd ALARM
LEFT OUTER JOIN NEW_CONFIG_DB.PROBABLE_CAUSE PROBC ON (ALARM.HISM_PROBABLE_CAUSE = PROBC.PROBABLE_CAUSE_ID)
LEFT OUTER JOIN (NEW_CONFIG_DB.EQP_NAME EQP
LEFT OUTER JOIN (CMM_DB.CMM_EQP_TYPE_REVISION ETYPE
INNER JOIN CMM_DB.CMM_VENDOR VEN ON (ETYPE.VENDOR_ID = VEN.VENDOR_ID))
ON (EQP.EQP_TYPE_NAME = ETYPE.EQP_TYPE_NAME))
ON (ALARM.HISM_EQP_NAME = EQP.EQP_NAME);
Perspektywa 2 :
CREATE OR REPLACE VIEW HISTORY_DB.VW_FAM_REPORTER_2 AS
SELECT /*+ PARALLEL(A) */
-- normalne rzeczy + trochę case'ów -> już pracuję nad optymalizacją
FROM
history_db.VW_ALARM_MAIN_2 A
WHERE
A.HISM_REPEATED_COUNT= 1
Zapytanie :
SELECT /*+ PARALLEL(r2) */
--normalny select
FROM
HISTORY_DB.VW_FAM_REPORTER_2 r2
WHERE
(r2.HISM_DATETIME_UP BETWEEN '2010-03-26 00:00:00' AND '2010-03-28 00:00:00'
OR
(r2.HISM_DATETIME_UP <= '2010-03-28 00:00:00' and r2.HISM_DATETIME_DOWN BETWEEN '2010-03-26 00:00:00' AND '2010-03-28 00:00:00'))
-- pozostałe warunki nie sprawiają problemów
Partycje zrobione na polu hism_datetime_up
Z góry dzięki za wszelką pomocGrzegorz Drzymała edytował(a) ten post dnia 26.04.10 o godzinie 22:11