Optymalizacja dostępu do zasobów

Optymalizacja dostępu do zasobów

Krzysztof Mikołajczyk

W trakcie działania bazy danych wielu użytkowników (a także procesy systemowe) korzysta z tych samych zasobów. Problem powstaje, gdy kilka procesów chce skorzystać na raz z tego samego zasobu, np. użytkownik chce odczytać pewne dane z dysku, ale w obszarze SGA nie ma wolnych buforów, co powoduje uaktywnienie procesu DBWR (ale proces użytkownika musi czekać). O wiele lepszą sytuacją jest, gdy DBWR przygotuje wolne bufory wcześniej.
Poniżej krótko omówione zostały podstawowe procesy i ich wpływ na wydajność.

Mechanizm zapisu dziennika – LGWR.

  • zapisuje za każdym potwierdzeniem użytkownika,
  • zapisuje, gdy określona część buforów jest zajęta,
  • może być uaktywniony przez DBWR,
  • każdy proces modyfikujący dane zapisuje do buforów dziennika,
  • jest prawie ciągle aktywny,
  • urządzenie dyskowe powinno być najszybsze z dostępnych.

Mechanizm zapisu do bazy danych – DBWR

  • dokonuje zapisu, gdy są potrzebne wolne bufory,
  • często wykorzystywane tablice i indeksy mogą być powodem wąskich gardeł,
  • nie jest to tak blokujące, jak LGWR.

Procesy pierwszoplanowe.

  • czytają bloki bazy z dysku do pamięci,
  • czytają z tych samych plików, do których DBWR dokonuje zapisu,

DBWR

Poszukiwanie wolnych buforów przez procesy użytkowników odbywa się wg zasady LRU (najdawniej użytych). W pierwszej kolejności wykorzystywane są bufory, które najdłużej nie były używane. Na żądanie procesu użytkownika system rozpoczyna przeszukiwanie listy LRU aż do momentu znalezienia wolnego (dane w buforze zgodne z danymi na dysku) lub do przeszukania ilości DB_BLOCK_MAX_SCAN_CNT buforów (parametr init.ora) bez znalezienia wolnego. Drugi przypadek powoduje uaktywnienie procesu DBWR, który musi „oczyścić” część buforów.
Bufory, w których dane zostały zmodyfikowane, trafiają na listę buforów „zanieczyszczonych” (dirty) – bufory te muszą być skopiowane na dysk przez DBWR, zanim będą mogły być użyte przez procesy użytkowników.

Proces DBWR jest uaktywniany w następujących przypadkach:

  • po przeszukaniu DB_BLOCK_MAX_SCAN_CNT nie ma wolnego bufora,
  • po dopisaniu przez proces użytkownika do listy buforów zanieczyszczonych zawiera ona DB_BLOCK_WRITE_BATCH/2 elementów,
  • co 3 sekundy (timeout),
  • w momencie wykonania punktu kontrolnego (na żądanie LGWR)

Strojenie polegać będzie na modyfikacji parametrów init.ora:

  • DB_BLOCK_MAX_SCAN_CNT – bez zmian (jeżeli po przeszukaniu tej ilości buforów nie zostanie znaleziony wolny, to DBWR będzie pobudzony do działania)
  • DB_WRITER_MAX_SCAN_CNT – bez zmian (taką część listy LRU przeszukuje DBWR, aby uzupełnić listę do DB_BLOCK_WRITE_BATCH/2)
  • DB_BLOCK_WRITE_BATCH: – parametr ten określa, ile buforów zanieczyszczonych będzie przepisanych jednorazowo na dysk.

Pierwsze dwa parametry na ogół można pozostawić bez zmian, zwiększenie trzeciego parametru powoduje:

  • sąsiednie bloki mogą być zapisane na raz,
  • dwa dyski mogą być zapisywane w tym samym czasie,
  • zmniejsza częstość pobudzania DBWR przez proces użytkownika,
  • zwiększa ilość bloków zapisywanych na raz.

Statystyki pomocne przy strojeniu procesu DBWR:

  • dbwr free low – ile razy DBWR pisze, ponieważ lista buforów zmodyfikowanych (dirty) osiągnęła wartość DB_BLOCK_WRITE_BATCH/2
  • free buffer inspected – liczba pominiętych buforów przed znalezieniem wolnego,
  • dbwr free needed – ile razy DBWR wykonał zapis, ponieważ proces użytkowy przeszukał db_block_max_mod_cnt część listy LRU bez znalezienia wolnego bufora,

Wartość parametru dbwr free needed powinna wynosić 0. Jeśli tak nie jest, to należy rozważyć zwiększenie parametru init.ora DB_WRITERS (oznacza on, ile jest uruchomionych procesów DBWR). Nie należy jednak zwiększać tego parametru ponad miarę, gdyż może to spowodować zmniejszenie wydajności (więcej procesów w systemie). Można również rozważyć zwiększenie parametru DB_BLOCK_WRITE_BATCH.

Mechanizm zapisu dziennika – LGWR
Zapisuje dane do plików dziennika powtórzeń.
Bufory zapisywane są sekwencyjnie.
Wykonuje zapis podczas wykonania punktu kontrolnego.
Zapisuje "prawie" bez przerwy.

Sposób działania:

  1. Proces pierwszoplanowy alokuje obszar w buforze dziennika powtórzeń, używając rezerwacji alokacji.
  2. Jeśli ilość danych jest mniejsza, niż "LOG_SMALL_ENTRY_MAX_SIZE", wtedy dane są kopiowane.
  3. Jeśli ilość danych jest większa, niż "LOG_SMALL_ENTRY_MAX_SIZE", wtedy rezerwacja alokacji jest zwalniana i używana jest rezerwacja kopiowania.
  4. Do kopiowania danych do buforów dziennika niezbędna jest rezerwacja.

LGWR używa rezerwacji alokacji i wszystkich rezerwacji kopiowania (i zwalnia je natychmiast) do kopiowania danych na dysk (w pełnych blokach systemu operacyjnego). Jeżeli system posiada jeden procesor (CPU_COUNT=0), to LGWR zawsze używa rezerwacji alokacji.

Sytuacje, w których LGWR jest zmuszony do czyszczenia buforów:

  • proces użytkowy dokonuje potwierdzenia,
  • bufory dziennika powtórzeń są pełne (zapisane w jednej trzeciej),
  • DBWR chce zapisać dane na dysk, a odpowiednie dane dziennika są jeszcze w buforze.
  • w trakcie wykonania punktu kontrolnego.

Eliminacja wąskiego gardła LGWR:

  • pliki dziennika powinny być na szybkim urządzeniu zewnętrznym,
  • zwiększenie rozmiaru buforów dziennika,
  • zmniejszenie ilości punktów kontrolnych,

Punkty kontrolne występują, gdy LGWR musi przełączyć się na inny plik dziennika lub gdy została osiągnięta LOG_CHECKPOINT_INTERVAL buforów zapisanych (chodzi o bufory systemu operacyjnego, a nie ORACLE’a). Punkt kontrolny synchronizuje LGWR i DBWR. Jeśli ustawimy wartość parametru LOG_CHECKPOINT_INTERVAL na większą, niż wielkość plików dziennika powtórzeń, to punkty kontrolne będą występować tylko w momencie przełączania plików dziennika (wtedy musi wystąpić). Dodatkowo, jeśli zwiększymy rozmiar plików dziennika, to dodatkowo zmniejszymy częstotliwość występowania punktów kontrolnych, ale może utrudnić odtwarzanie po awarii.
W przypadku awarii instancji odtwarzanie nastąpi od ostatniego punktu kontrolnego. Im częściej występuje punkt kontrolny, tym szybciej takie odtwarzanie zakończy się (należy tu brać pod uwagę wielkość plików kontrolnych).
W wersji 7 można odciążyć proces LGWR poprzez uruchomienie dodatkowego procesu CKPT, który będzie realizował wykonanie punktów kontrolnych (parametr init.ora CHECKPOINT_PROCES ustawiony na TRUE).
W wersji 7 można również wymuszać wykonanie punktu kontrolnego po upływie określonego czasu (parametr init.ora LOG_CHECKPOINT_TIMEOUT, domyślnie ustawiony na 0). Jeśli nie występują specjalne powody, to należy pozostawić ten parametr bez zmian.
LGWR alokuje przestrzeni w pliku dziennika powtórzeń w porcjach po „LOG_ALLOCATION” (parametr pliku init.ora – tylko w wersji 6). W systemach z jedną instancją na bazę parametr ten powinien być ustawiony na wartość większą od rozmiaru największego pliku dziennika (ponieważ tylko jedna instancja alokuje przestrzeń).
Statystyką pomocną przy strojeniu buforów dziennika powtórzeń jest redo log space waittime (znajduje się w V$WAITSTAT), która oznacza, ile razy proces użytkownika musiał czekać ze względu na brak wolnych buforów dziennika. Ta statystyka powinna mieć ZAWSZE wartość 0. W przeciwnym przypadku należy zwiększyć LOG_BUFFER.

Należy również zadbać o odpowiednie wykorzystanie rezerwacji. Należy skorzystać ze statystyk redo allocation i redo copy. Jeśli stosunek „misses/gets” jest wiekszy od 1%, to należy przedsięwziąć pewne akcje. Aby usunąć spory przy dostępie do rezerwacji redo allocation, należy rozważyć zmniejszenie LOG_SMALL_ENTRY_MAX_SIZE (częściej będzie używana rezerwacja redo copy). Aby usunąć spory przy dostępie do rezerwacji redo copy, należy zwiększyć parametr LOG_SIMULTANOUS_COPIES, który zwiększy ilość rezerwacji (dotyczy to tylko komputerów wieloprocesorowych – w jednoprocesorowych zawsze używane są redo allocation). Można również zwiększyć parametr init.ora LOG_ENTRY_PREBUILD_THRESHOLD, który spowoduje, że żądania mniejsze od tej wartości (w bajtach) będą przygotowane przez proces użytkownika przed żądaniem rezerwacji.

Segmenty wycofania
Segmenty wycofania przechowują dane z aktualnie wykonywanych transakcji. Dzięki temu pozwalają wycofać transakcję, a także dokonywać odczytu danych podczas ich modyfikacji.
Transakcje nie mogą być większe od rozmiaru segmentu wycofania. Jeśli transakcja osiągnie wielkość segmentu wycofania przed zakończeniem, to system automatycznie powiększa segment wycofania (o ile to możliwe). Po zakończeniu transakcji segment wycofania może zostać automatycznie zmniejszony (tylko w wersji 7). Aby stwierdzić, czy w systemie występują spory, należy sprawdzić statystyki db block gets, consistent gets oraz buffer busy waits. Jeśli stosunek

buffer busy waits/(db block gets + consistent gets)

jest większy od 10%, to występuje spór przy dostępie do segmentów wycofania.
Przyjmuje się, że liczba segmentów wycofania wynosi jeden na czterech użytkowników, ale nie więcej niż 50.
W większości przypadków wszystkie segmenty wycofania powinny być tej samej wielkości. Jeżeli w systemie występuje dużo małych transakcji, to powinno być wiele małych segmentów. Jeżeli w systemie występują głównie długotrwałe transakcje, to powinno być kilka dużych segmentów wycofania. Jeśli w systemie mamy duże i małe transakcje, to dla dużych transakcji należy użyć polecenia SET TRANSACTION USE ROLLBACK SEGMENT rbs, gdzie rbs oznacza nazwę dużego segmentu wycofania.

Krzysztof Mikołajczyk