2011-11-21 10 views
5

Mam zmaterializowany widok w Oracle, który zawiera LEWY DOŁĄCZ, co zajmuje bardzo dużo czasu na aktualizację. Kiedy aktualizuję tabelę bazową, potrzeba 63914.765 s (tak, to prawie 17 godzin).Oracle - SZYBKI ODŚWIEŻ Materialized views with LEFT JOINS aktualizacje bardzo powolne

Używam LEFT JOIN w tej samej tabeli, ponieważ chcę przestawić dane z wierszy do kolumn. Polecenie przestawne nie jest dostępne w tej wersji Oracle, a użycie funkcji GROUP BY + CASE nie jest dozwolone w widoku zmaterializowanym SZYBKIEGO ODŚWIEŻENIA.

zmaterializowanej View Log wygląda następująco:

CREATE MATERIALIZED VIEW LOG ON Programmes_Titles 
WITH PRIMARY KEY, rowid 
INCLUDING NEW Values; 

zmaterializowanej sama View wygląda następująco (zawiera 700000 wiersze tabela Programmes_Titles zawiera 900000 wierszy):

CREATE MATERIALIZED VIEW Mv_Web_Programmes 
REFRESH FAST ON COMMIT 
AS 

SELECT 
    t1.ProgrammeId,   
    t1.Title as MainTitle, 
    t2.Title as SecondaryTitle, 
    --Primary key 
    t1.Title_Id as t1_titleId, 
    t2.Title_Id as t2_titleId, 

    t1.rowid as t1_rowid, 
    t2.rowid as t2_rowid 
FROM 
    Programmes_Titles t1, 
    Programmes_Titles t2 
WHERE 
    t1.Titles_Group_Type = 'mainTitle' 
    AND t1.Programme_Id = t2.Programme_Id(+) AND t2.Titles_Group_Type(+) = 'secondaryTitle' 

Instrukcja UPDATE Używam:

UPDATE Programmes_Titles 
SET Title = 'New title' 
WHERE rowid = 'AAAL4cAAEAAAftTABB' 

Ta instrukcja UPDATE kes 17 godzin. Gdy używasz INNER JOIN (usuń (+)), zajmuje to milisekundy.

Próbowałem również dodawać INDEXES w zmaterializowanym widoku Mv_Web_Programmes, ale to też nie pomagało. (Ciągle trwa dłużej niż minutę, co jest powolne, nie czekam 17 godzin po każdej zmianie, więc może poprawić AKTUALIZACJĘ)

Moje pytanie brzmi: dlaczego zajmuje tak dużo czasu AKTUALIZOWAĆ podstawową tabelę? Jak mogę to poprawić?

Odpowiedz

3

Udało mi się odtworzyć Twój problem w instancji 10.2.0.3. Samo-zewnętrzne sprzężenie wydaje się być głównym problemem (chociaż z indeksami w każdej kolumnie MV w końcu zaktualizował się w niecałą minutę).

Na początku myślałem, że można użyć zagregowany MV:

SQL> CREATE MATERIALIZED VIEW LOG ON Programmes_Titles 
    2 WITH PRIMARY KEY, ROWID (programmeId, Titles_Group_Type, title) 
    3 INCLUDING NEW Values; 

Materialized view log created 

SQL> CREATE MATERIALIZED VIEW Mv_Web_Programmes 
    2 REFRESH FAST ON COMMIT 
    3 AS 
    4 SELECT ProgrammeId, 
    5   MAX(decode(t1.Titles_Group_Type, 'mainTitle', t1.Title)) MainTl, 
    6   MAX(decode(t1.Titles_Group_Type, 'secondaryTitle', t1.Title)) SecTl 
    7 FROM Programmes_Titles t1 
    8 GROUP BY ProgrammeId; 

Materialized view created 

Niestety, jak zauważyłeś, poczynając od 10g a MV that contains MIN or MAX can only be fast-refreshed on commit after insert (tzw wkładka tylko MV). Powyższe rozwiązanie nie działałoby dla aktualizacji/usuwania (MV musiałoby zostać odświeżone ręcznie).

Można prześledzić sesję i otworzyć plik śledzenia, aby zobaczyć, jakie zapytanie SQL zostanie wykonane, aby można było sprawdzić, czy można go zoptymalizować za pomocą indeksów.

+0

Dziękuję, sugerowane rozwiązanie działa idealnie. Tylko jedno dodatkowe pytanie. W moim przykładowym zapytaniu używam tylko jednego kryterium w JOIN, ale moje prawdziwe zapytanie używa dwóch. Czy nadal mogę korzystać z funkcji DECODE (jest to dla mnie nowe, czy zamiast tego powinienem użyć CASE?) – Tejo

+0

Przepraszam, byłem trochę szybki. Tabela programu Programme_Titles jest aktualizowana o nową wartość poniżej sekundy, ale Mv_Web_Programmes nie jest aktualizowany, stara wartość nadal istnieje. Jakieś pomysły? – Tejo

+0

Powinieneś być w stanie używać CASE zamiast DECODE, o ile każda kolumna, której używasz w swoim CASE, również znajduje się w logu MV. –

1

My też w obliczu tego problemu niedawno na Oracle 11.2.0.3

W naszym przypadku było to nieuniknione, aby wyjąć „OUTER JOIN” ze względu na oddziaływania funkcjonalnego.

Po przeprowadzeniu dochodzenia stwierdzono, że Oracle dodawał nieprzyjemną wskazówkę HASH_SH (Hash Semi Join) z odświeżaniem MV w MV.

Nic nie działało w tym rzeczy wspomnianych w następujących blog- http://www.adellera.it/blog/2010/03/11/fast-refresh-of-join-only-mvs-_mv_refresh_use_stats-and-locking-log-stats/#comment-2975

W końcu, ukryta aluzja pracował ... (choć na ogół należy unikać dokonywania zmian w aplikacji jeśli to możliwe)

Oracle Doc ID 1949537.1 sugeruje, że ustawienie ukrytego parametru _mv_refresh_use_hash_sj na FALSE powinno uniemożliwić użycie tej wskazówki.

alter session set "_mv_refresh_use_hash_sj"=FALSE; 

To zatrzymało CBO przy pomocy wskazówki HASH_SJ.

Publikowanie tutaj w interesie innych osób.