Download - Systemy zarządzania bazami danych
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
1
Systemy zarządzania bazami danych
7. Wskazówki dla optymalizatora
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
2
Wskazówki dla optymalizatora
• Wskazują plan najlepszy wg programisty • Usztywniają plan wykonania zapytania
– Jeśli coś się w bazie zmieni, nie zmieni się plan
• Czasem są nieodzowne (gdy optymalizator sobie nie radzi, a aplikacja musi przecież działać)
• Lepiej ich jednak unikać• Dalsza część wykładu jest też pokazem
bogactwa opcji optymalizacyjnych
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
3
Ścieżka dostępu• Zrób full scan:
SELECT /*+ FULL(e) */ employee_id, last_name
FROM employees e
WHERE last_name LIKE :b1;
• Nie używaj indeksu: SELECT /*+ NO_INDEX(e emp_empid) */
employee_id FROM employees eWHERE employee_id > 200;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
4
Indeksowe ścieżki dostępu• Użyj indeksu:
SELECT /*+ INDEX (e emp_department_ix)*/ *FROM employees eWHERE department_id > 50;
• Zrób fast full scan indeksu: SELECT /*+ INDEX_FFS(e emp_name_ix) */
first_name FROM employees e;
• Zrób skip scan indeksu: SELECT /*+ INDEX_SS(e emp_name_ix) */ last_name
FROM employees e WHERE first_name = 'Steven';
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
5
Operuj mnogościowo na indeksach
SELECT /*+ INDEX_COMBINE(e emp_manager_ix emp_department_ix) */ *
FROM employees e WHERE manager_id = 108 OR department_id = 110;
SELECT /*+ INDEX_JOIN(e emp_manager_ix emp_department_ix) */ department_id
FROM employees e WHERE manager_id < 110 AND department_id < 50;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
6
Transformacje zapytania• Bez transformacji
SELECT /*+ NO_QUERY_TRANSFORMATION */ employee_id, last_name
FROM (SELECT * FROM employees e) v
WHERE v.last_name = 'Smith'; • Zamień OR na UNION ALL
SELECT /*+ USE_CONCAT */ * FROM employees e WHERE manager_id = 108 OR department_id = 110;
• Nie rób tego: /*+ NO_EXPAND */
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
7
Użyj widoków zmaterializowanych
• Użyj:SELECT /*+ REWRITE(s) */ t.calendar_month,
sum(s.amount_sold) AS dollars FROM sales s, times t WHERE s.time_id = t.time_id GROUP BY t.calendar_month desc;
• Nie używaj: /*+ NO_REWRITE */
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
8
Widok zmaterializowanyCREATE MATERIALIZED VIEW salesByTid
REFRESH NEXT Sysdate + 1 ASSELECT s.time_id, sum(s.amount_sold) AS dollars
FROM sales sGROUP BY s.time_id;
• To jest agregacja, której możemy użyć
• Potrzebujemy bowiem grubszej agregacji
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
9
Wynik przepisania• Początkowe zapytanie
SELECT /*+ REWRITE(s) */ t.calendar_month, sum(s.amount_sold) AS dollars
FROM sales s, times t WHERE s.time_id = t.time_id GROUP BY t.calendar_month desc;
• Po przepisaniu i użyciu widoku salesByTid:SELECT t.calendar_month, sum(s.dollars) AS dollars
FROM salesByTid s, times t WHERE s.time_id = t.time_id GROUP BY t.calendar_month desc;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
10
Rozwiń definicję widoku
• Rozwiń (też lokalnego jak tu)SELECT /*+ MERGE(v) */ e1.last_name, e1.salary, v.avg_sal
FROM employees e1, (SELECT department_id, avg(salary) avg_sal FROM employees e2 GROUP BY
department_id) vWHERE e1.department_id = v.department_id
AND e1.salary > v.avg_salary;
• Nie rozwijaj /*+ NO_MERGE */
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
11
Po rozwinięciu definicji widoku
• Po zmianachSELECT e1.last_name, e1.salary, avg(e2.salary)
FROM employees e1, employees e2WHERE e1.department_id = e2.department_id GROUP BY e1.last_name, e1.salary, e2.department_idHAVING e1.salary > avg(e2.salary);
• Czy jest lepiej?• Raczej koszmarnie, bo wynik pośredniego
złączenia jest ogromny (jak iloczyn kartezjański)
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
12
Rozwiń podzapytania
• Rozwiń /*+ UNNEST */
• Nie rozwijaj /*+ NO_UNNEST */
SELECT /*+ UNNEST */ titleFROM StarsInWHERE starName IN (SELECT name
FROM MovieStarWHERE birthdate LIKE
‘%1960’);
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
13
Transformacja STAR
• WykonajSELECT /*+ STAR_TRANSFORMATION */ *
FROM sales s, times t, products p, channels c WHERE s.time_id = t.time_id
AND s.prod_id = p.product_id AND s.channel_id = c.channel_id
AND p.product_status = 'obsolete';
• Nie wykonuj /*+ NO_STAR_TRANSFORMATION */
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
14
Po transformacji STAR
• Użyteczne w hurtowniach dla tabel faktów• Gdy są indeksy bitmapowe
SELECT *FROM sales sWHERE s.prod_id IN (SELECT product_id FROM products
WHERE p.product_status = 'obsolete‘)
• Potem wynik jest łączony z tabelami wymiarów (products, channels, times)
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
15
Wskazanie faktów i wymiarów
• Tabela faktów /*+ FACT(sales) */
• Tabela wymiarów /*+ NO_FACT(products) */
SELECT /*+ STAR_TRANSFORMATION FACT(s) NO_FACT(t) NO_FACT(p) NO_FACT(c) */ * FROM sales s, times t, products p, channels cWHERE ...
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
16
Kolejność złączeń• Wskazana we wskazówce
SELECT /*+ LEADING(e j) */ * FROM employees e, departments d, job_history j WHERE e.department_id = d.department_id AND e.hire_date = j.start_date;
• Wg kolejności w klauzuli FROMSELECT /*+ORDERED */ o.order_id, c.customer_id, l.unit_price * l.quantity FROM customers c, order_items l, orders o WHERE c.cust_last_name = :b1 AND o.customer_id = c.customer_id AND o.order_id = l.order_id;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
17
Metoda złączenia (iteracja)• Iteracja (lista preferowanych tabel wewnętrznych)
– Tabela orders będzie zewnętrznaSELECT /*+ USE_NL(l h) */ h.c_id, l.unit_price * l.quantity
FROM orders h ,order_items l WHERE l.order_id = h.order_id;
• Iteracja z indeksemSELECT /*+ USE_NL_WITH_INDEX(l item_order_id _ix)*/ *
FROM orders h, order_items l WHERE l.order_id = h.order_id AND h.order_id > 3500;
• Wyklucz złączenie iteracyjne /* NO_USE_NL */
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
18
Metoda złączenia (scalanie)
• Użyj złączenia przez scalanieSELECT /*+ USE_MERGE(e d) */ *
FROM employees e, departments dWHERE e.department_id = d.department_id;
• Wyklucz złączenie przez scalanieSELECT /*+ NO_USE_MERGE(e d) */ *
FROM employees e, departments d WHERE e.department_id = d.department_id ORDER BY d.department_id;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
19
Metoda złączenia (haszowanie)
• Użyj złączenia haszowanegoSELECT /*+ USE_HASH(l h) */ *
FROM orders h, order_items l WHERE l.order_id = h.order_id
AND l.order_id > 3500;
• Wyklucz złączenie haszowaneSELECT /*+ NO_USE_HASH(e d) */ *
FROM employees e, departments d WHERE e.department_id = d.department_id;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
20
Przetwarzanie równoległe• Określamy równoległość
SELECT /*+ FULL(e) PARALLEL(e, 5) */ nameFROM employees e;
• Równoległość domyślna dla tabeliSELECT /*+FULL(e) PARALLEL(e, DEFAULT)*/ *
FROM employees eWHERE hiredate < SYSDATE – 100;
• Wykonaj sekwencyjnieSELECT /*+ NO_PARALLEL(hr_emp) */
last_name FROM employees hr_emp;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
21
Partycjonowanie tabel
• Określamy sposób podziału tabeli przed przetwarzaniem równoległym– Hash – podziel przez haszowanie– Partition – partycjonuj tabelę zgodnie
z jakimś przepisem (np. drugiej tabeli)– Broadcast – wyślij całość do każdej
partycji– None – użyj fizycznego
partycjonowania tabeli
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
22
Kombinacje partycjonowania
• Hash, hash (pierwsza jest zewnętrzna)– Podziel obie tabele funkcją haszującą
• Broadcast, None LUB None, Broadcast– Użyj partycjonowania jednej tabeli (None) a
drugą (Broadcast) wyślij do całości do serwera każdej partycji pierwszej tabeli
• Partition, None LUB None, Partition– Użyj partycjonowania jednej tabeli (None) do
podziału drugiej na partycje (Partition)
• None, None– Złącz tylko pasujące partycje. Obie tabele
muszą być tak samo partycjonowane
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
23
Przykłady partycjonowania• Rozrzuć zawartość tabel za pomocą
funkcji haszującejSELECT /*+PQ_DISTRIBUTE(HASH, HASH)*/ *
FROM r,s WHERE r.c=s.c;
• Użyj partycjonowania tabeli s, roześlij całą rSELECT /*+ ORDERED
PQ_DISTRIBUTE(BROADCAST, NONE )*/ * FROM r,s WHERE r.c=s.c;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
24
Równoległe użycie indeksu• Jak bardzo ma być zrównoleglone
przeszukiwane zakresowe? SELECT /*+PARALLEL_INDEX(e,emp_name,5 )*/ *
FROM employee eWHERE e.name LIKE ‘Smi%’;
• Nie zrównoleglaj przeszukiwania indeksu: SELECT /*+NO_PARALLEL_INDEX(e)*/ *
FROM employee eWHERE e.name LIKE ‘Smi%’;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
25
Staraj się trzymać w RAM
• Tzn. wstaw na koniec kolejki LRUSELECT /*+ FULL(e) CACHE(e) */ last_name
FROM employees hr_emp;
• Albo: wstaw na poczatek kolejki LRU (zrób MRU)SELECT /*+ FULL(e) NOCACHE(e) */
last_name FROM employees hr_emp;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
26
Predicate move-around• Przesuń warunek do widoku (też inline)
SELECT /*+ NO_MERGE(v) PUSH_PRED(v) */ * FROM employees e,
(SELECT manager_id FROM employees ) v WHERE e.manager_id = v.manager_id(+)
AND e.employee_id = 100;
• Robi się złączenie zależne:SELECT * FROM employees e LEFT JOIN
(SELECT manager_id FROM employees WHERE e.manager_id = manager_id)
WHERE e.employee_id = 100;
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
27
Predykaty, kolejności...
• Nie przenoś predykatów /*+ NO_PUSH_PRED(v)*/
• Oblicz podzapytanie najpierw: SELECT /*+ NO_MERGE(v) PUSH_SUBQ(v) */ *
FROM employees e, (SELECT manager_id FROM
employees ) v WHERE e.manager_id = v.manager_id(+)
AND e.employee_id = 100;
• Oblicz podzapytanie na końcu /*+NO_PUSH_SUBQ(v)*/
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
28
Miejsce obliczeń
• Wskazujemy zdalną lokalizację do wykonania obliczeń: SELECT /*+ DRIVING_SITE(d) */ *
FROM employees e, departments@rsite dWHERE e.department_id = d.department_id;
• Bez wskazówki obliczenie byłoby lokalne ze ściągnięciem tabeli departments z serwera rsite
• Ze wskazówką obliczenie odbędzie się na rsite po wysłaniu tam tabeli employees
Oryginał: Oracle Corp. 7. Wskazówki dla optymalizatora
29
Dynamiczne próbkowanie
• Dynamiczne próbkowanie polega na odrzuceniu zapamiętanych statystyk i użyciu oszacowań wynikających z próbkowania danych (np. ocena selektywności warunku)
• Poziom próbkowania to liczba całkowita z zakresu od 0 do 10 (poziom 10 oznacza najdokładniejsze próbkowanie)SELECT /*+ DYNAMIC_SAMPLING(e 1) */ *
FROM employees eWHERE salary BETWEEN 1007 AND 2356;