niedziela, 4 grudnia 2011

Wprowadzenie do Optymalizatora Kosztowego

Kolejne kroki wykonywania zapytania SQL


Stworzenie kursora (CREATE CURSOR)

Kursor jest uchwytem do przestrzeni przeznaczonej na informacje niezbędne do przetworzenia zapytania. Podczas wykonywania zapytania kursor będzie zawierał pointer do aktualnie przetwarzanego wiersza. Jeśli miałeś do czynienia z PL/SQL – dane pobierane są w momencie fetchowania wiersza. Znajdziejsz tutaj wskaźnik na ten aktualnie pobierany wiersz. Kursory przetwarzane są liniowo wiersz po wierszu. Pointer będzie się przesuwał do kolejnego wiersza.

Parsowanie zapytania (PARSE)

Sprawdzane jest czy wcześniej zostało wykonane to zapytanie i czy można wykorzystać explain plan stworzony dla wcześniejszego zapytania. Explain plany będą znajdować się w shared_pool. Metodą analogii – wracając do naszego przykładu z podróżą. Jeśli jechałem w zeszłym tygodniu z Gdyni do Krakowa, stworzyłem sobie mapkę na której zaznaczyłem w jaki sposób mam dojechać z miejsca na miejsce. Oznaczyłem postoje, spośród kilku możliwych tras wybrałem jedną. Jeśli zechcę po raz kolejny jechać tą trasą a mam jeszcze mapkę (explain plan znajduje się nadal w shared_pool) mogę ją wykorzystać. Tak samo jeśli przyjdzie do mnie kolega i poprosi o wypożyczenie mu mapki , udostępnię mu ją by mógł zmniejszyć sobie ilość pracy związanej z planowaniem podróży. Tak to działa przy wykonywaniu zapytania. Jeśli wykonam zapytanie i powstanie przy tym plan jego wykonania ( explain plan - zawierający informacje co gdzie leży i jak się do tego dobrać) to przy kolejnym wykonaniu tego samego zapytania mogę wykorzystać wcześniej stworzony plan. Zapytania innych użytkowników również mogą wykorzystać ten sam plan. Jeśli będę tym razem jechał z Łodzi do Krakowa, to mimo że cel jest ten sam trasa będzie się różnić i nie mogę wykorzystać wcześniej stworzonej mapki. Z tego właśnie powodu zapytania muszą być identyczne (co do spacji) by mogły współdzielić plan wykonania.
W tym miejscu sprawdzana jest poprawność składniowa zapytania, fakt posiadania lub nie uprawnień do obiektów. Jeśli znalazł się w shared_pool plan wykonania który można wykorzystać, jest wykorzystywany. Jeśli go tam nie było, jest tworzony i wrzucany do shared_pool.

Opisanie wyniku (DESCRIBE)

Opisanie kształtu wyniku zapytania. W tym etapie sprawdzane jest jak będzie wyglądać wynik tj. jakie będzie zawierał kolumny i jakiego typu.

Definicja (DEFINE)

Definiowany jest typ danych oraz wielkość zmiennych używanych do pobierania wyniku zapytania.

Podpinanie zmiennych (BIND)

W tym miejscu wszelkie zmienne zamieniane są na wartości – np. zmienne bindowane. Zauważ że sprawdzanie wartości zmiennych bindowanych odbywa się już po poszukiwaniu explain planu. Zapamiętaj to, bo będzie to ważne podczas jednej z technik optymalizacji.

Zrównoleglenie procesów (PARALLELIZE)

Niektóre elementy zapytania mogą być od siebie niezależne. Jeśli tak jest, powstaje kilka osobnych procesów w których te elementy są wykonywane równolegle zamiast liniowo. Dzięki temu zapytanie wykonuje się szybciej.



Wykonanie (EXECUTE)

Baza ma już wszystkie niezbędne informacje, więc zapytanie jest wykonywane. Jeśli jest to delete lub update, blokowane są odpowiednie wiersze do czasu zakonczenia transakcji.

Pobranie danych (FETCH)

Dane są pobierane wiersz po wierszu do zdefiniowanych w etapie DEFINE zmiennych. Wynik zapytania zwracany jest w postaci tabeli.

Zamknięcie kursora (CLOSE CURSOR)

Odpinana jest referencja do obszaru pamięci przeznaczonego na kursor dzięki czemu może zostać ponownie wykorzystana.


Do czego służy optymalizator kosztowy?




Optymalizator kosztowy opierając się o statystyki i dostępne struktury danych wytwarza plany wykonania zapytania. Bierze pod uwagę dostępne indeksy i obmyśla kilka możliwości dostępu do danych. Powrót do analogii z podróżą: siadamy i mając za zadanie dotrzeć do Krakowa sprawdzamy różne możliwości. Mamy więc możliwość dotarcia pociągiem, samolotem, samochodem , motorem. W przypadku tych 2 ostatnich mogę jeszcze wybrać kilka możliwych dróg. Kiedy już będę miał wszystkie możliwości, usiądę i policzę ile czasu , oraz jak bardzo mnie zmęczy dotarcie do celu z wykorzystaniem każdej z tych możliwości. Wybiorę oczywiście tą najszybszą i najmniej męczącą. Optymalizator kosztowy określi koszt dla każdego planu wykonania i wybierze ten plan który będzie miał najniższy koszt. W trakcie szacowania kosztów Twojego zapytania CBO (cost based optimizer – optymalizator kosztowy) może przetworzyć Twoje zapytanie na analogiczne, ale inaczej skonstruowane i wyliczyć koszt również dla tego analogicznego.
Optymalizator kosztowy określa podczas opracowywania planów 3 rzeczy. Koszt, selektywność i liczebność.



Selektywność  (selectivity)
selektywność=ilość wierszy pobranych/całkowita ilość wierszy. Przykładowo z tabeli zawierającej milion wierszy pobierzemy 100 spełniających jakiś warunek.
Informacje statystyczne na temat tabel znajdziesz w słownikach: dba_tables, dba_tab_statistics, dba_tab_cols_statistics. Optymalizator kosztowy sprawdza np. jaką część wierszy stanowią wiersze które spełniają warunek department_id=60. Informacje te sprawdza właśnie w statystykach oraz histogramach. Jeśli nie ma aktualnych statystyk dla tabeli wykorzystywany jest Dynamic Sampling.
Dynamic Sampling – Dynamiczne próbkowanie wykorzystywane jest gdy brak statystyk dla tabeli, lub gdy są one na tyle przestarzałe że nie można im ufać. Poziom próbkowania określa parametr optimizer_dynamic_sampling który możemy zweryfikować w słowniku v$parameter. Domyślnie ten parametr ustawiony jest na wartość 2. Dopuszczalne wartości mieszczą się w przedziale 0 do 2. 0 oznacza zupełne wyłączenie dynamicznego próbkowania. 1 – próbkowanie stosowane jest tylko w przypadku pełnego odczytu z obiektu (np. z tabeli). 2 to włączenie dynamic sampling, wyższe stopnie określają coraz bardziej agresywne próbkowanie.



Liczebność (cardinality)
cardinality=selektywność (( a właściwie jej stosunek procentowy do wszystkich wierszy w obiekcie) * całkowita liczba wierszy
Określa oczekiwaną liczbę wierszy zwrocona w wyniku zapytania.




Koszt (cost)
Jednostka niemetryczna. Określa szacunkową liczbę odczytów I/O niezbędną w celu wykonania zapytania. Wliczane są również operacje na pamięci operacyjnej, czy też cykle procesora niemniej ważne dla optymalizacji co ilość odczytów z dysku. W oparciu o tą wartość porównywane są plany wykonania.


Parametr CURSOR_SHARING



Określa jakie rodzaje zapytań SQL mogą współdzielić te same kursory (np. plany wykonania).
Zmieniamy go poleceniem :


ALTER SYSTEM SET CURSOR_SHARING='wartosc';


Wartości jakie może przyjmować:


Exact (domyślny): Kursory mogą współdzielić tylko zapytania o identycznej konstrukcji – co do znaku. Ma znaczenie wielkość liter i spacje.


Force: Pozwala na współdzielenie kursorów przez zapytania podobne (np. różniące się wielkością liter) o ile różnice w nich nie wpływają na sens zapytania.


Similar: Jak wyżej , z tym ze różnice nie mogą wpływać na wybór planu wykonania.



Parametr OPTIMIZER_FEATURES_ENABLE
Możesz zauważyć że na dwóch bazach danych wykonując to samo zapytanie na tych samych danych, a mając odświeżone statystyki na obu dostaniemy różne plany wykonania. To może wynikać ze zróżnicowania parametrów inicjalizacyjnych w tych dwóch bazach. W zalezności od tych ustawień oraz od wersji bazy , możemy mieć dostępne różne techniki automatycznej optymalizacji. Poniżej zestawienie niektórych możliwości w zależności od wersji bazy:


Własność Wersje 9.0.0 do 9.2.0 10.1.0 do 10.1.6 10.2.0 do 10.2.0.2 11.1.0.6
Fast Full Scan po indeksie X X X X
Zmienne bindowane X X X X
Łączenie tabel po indeksach X X X X
Dynamiczne próbkowanie - X X X
Query Rewrite - X X X
Pomijanie indeksów które są bezużyteczne (np. mają już zbyt wiele poziomów) - X X X
Automatyczne wyliczanie statystyk dla indeksów w momencie ich tworzenia - X X X
Automatyczne modyfikowanie zapytań w oparciu o koszt - X X X
Wykorzystanie rozszerzonych statystyk do określania selektywności - - - X




Ten parametr umożliwia nam ustawienie zgodności wykorzystywanych przez optymalizator technik dla konkretnej wersji bazy danych.








Sprawdzić wartość tego parametru możemy w ten sposób:
SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='optimizer_features_enable';
zmienić:
ALTER SYSTEM SET OPTIMIZER_FEATURES_ENABLE='10.1.0';



Po takiej zmianie optymalizator będzie stosował tylko własności dostępne dla danej wersji.


Brak komentarzy:

Prześlij komentarz