Sunteți pe pagina 1din 11

Optimizarea interogarilor in Oracle

Obiective
- Ce este SQL tuning ?
- Ce este optimizatorul ?
- Ce este un plan de executie SQL ?
- Cum se interpreteaza un plan de executie ?
- Operatorii optimizatorului:
- Unari: cai de acces
- Binari: join-uri
- N-ari
- Operatori Optimizator
- table access: full table scan, rowid scan, sample table scan
- index access: index scan unique, index scan range, index scan full/fast full/skip/index
join, bitmap index, combining bitmap index
- Operatori de Join
- metode join: nested loop, sort-merge, hash

1. SQL tuning.

SQL tuning reprezinta ansamblul de metodologii si instrumente Oracle aplicate pentru a


imbunatati performantele instructiunilor SQL. In Oracle, o instructiune SQL poate avea performante
slabe datorita unei palete largi de cauze:
− lipsa statisticilor folosite de optimizatorul bazei de date
− lipsa structurilor de acces la date cum ar fi indexii, view-urile materializate sau partitiile
− planuri de executie ne-optime pentru instructiuni SQL
− instructiuni SQL cu o sintaxa deficitara si ineficienta
Serverul Oracle are mecanisme automate de colectarea, procesarea si stocarea informatiilor
statistice despre performantele proceselor serverului. Scopul gestionarii acestor statistici este de a
detecta problemele de performanta si de a le optimiza, pe cat posibil, in mod automat. Un astfel de
depozit de statistici Oracle este AWR – Automatic Workload Repository.
Statisticile includ informatii ale obiectelor bazei de date, date sistem si sesiune, date temporale,
date ale sesiunilor active (Active Session History – ASH). AWR genereaza automat instante
(„snapshots”) ale datelor de performanta de pe server.
De asemenea, Oracle pune la dispozitie o serie de instrumente de optimizare:
− ADDM – Automatic Database Diagnostic Monitor
− SQL Tuning Advisor
− SQL Tuning Sets
− SQL Access Advisor
− SQL Performance Analyzer
− SQL Monitoring
− SQL Plan Management

Principalele activitati in optimizarea performantelor instructiunilor SQL sunt:


− identificarea instructiunilor SQL neperformante
− generarea statisticilor sistem

1
− recrearea indexilor existenti
− actualizarea planurilor de executie
− crearea noilor strategii de indexare

Principalele cauze ale unui sistem cu baze de date Oracle ne-performante sunt:
− gestiunea defectuoasa a conexiunilor
− folosirea incorecta a cursorilor si zonelor de memorie comuna („shared pool”)
− multe instructiuni SQL care consuma in exces resursele sistemului
− initializarea non-standard a parametrilor
− configurarea incorecta a parametrilor de stocare pe disc a bazei de date
− probleme de configurare a fisierelor de tip redo-log
− serializarea excesiva
− folosirea inadecvata a scanarii totale a tabelelor
− numarul mare de instructiuni SQL recursive
− erori de migrare sau instalare in sisteme de productie

Pentru a preveni performantele slabe ale unei baze de date se recomanda folosirea unor metode
pro-active de optimizare:
− proiectare simpla folosind modelarea Entitate Relatie
− folosirea corecta a tipurilor de tabele si indexi
− folosirea eficienta a view-rilor
− scrierea eficienta a instructiunilor SQL
− folosirea variabilelor de legatura („bind variables”) si a tehnici „cursor sharing”

2. Optimizatorul serverului Oracle.

Procesarea unei instructiuni SQL pe server implica pasii urmatori:


− crearea unui cursor
− parsarea instructiunii
− descrierea rezultatului instructiunii
− definirea rezultatului instructiunii
− folosirea variabilelor de legatura („bind variables”)
− paralelizarea instructiunii
− executarea instructiunii
− extragerea liniilor rezultate
− inchiderea cursorului

Aceste etape sunt sugerate si in figura urmatoare:

2
Necesitatea folosirii unui optimizator este sugerata in figura urmatoare:

In exemplul din figura instructiunea poate fi executata in 2 moduri: fie se parcurge tabela linie
cu linie („full table scan”), fie se foloseste indexul existent („index table scan”). Optimizatorul este cel
care decide ce modalitate de extragere a rezultatului se aplica. Pentru a alege solutia optima,
optimizatorul foloseste mecanismul din figura:

Optimizatorul, pentru a genera un plan de executie, foloseste alte 2 mecanisme:


− transformatorul de instructiuni
− estimatorul bazat pe cost (CBO - Cost Based Estimator)
3
Mai jos sunt cateva exemple de transformare a unor instructiuni SQL:

Mecanismul de optimizare a interogarilor executa urmatoarele operatii:


- evaluarea expresiilor si conditiilor;
- transformarea instructiunilor: pentru comenzi complexe, de exemplu interogari corelate,
se poate transforma instructiunea initiala in instructiuni de tip join echivalente;
- alegerea scopului de optimizat: utilizarea resurselor sau timpul de raspuns;
- alegerea cailor de acces: alegerea unei cai sau mai multe de acces la datele necesare;

4
- alegerea ordinii in care sa fac join-urile: daca sunt implicate mai multe tabele se aleg
primele doua, apoi rezultatul este combinat cu a treia tabela etc
Mecanismul de optimizare a interogarilor determina care plan de executie este mai eficient
considerant mai multi factori:
- caile de acces la date disponibile;
- informatiile statistice din dictionarul de date despre tabelele, indexii si celelalte obiecte
referite in interogare;
- eventuale „hint-uri” introduse intre comentarii in cadrul instructiunii;
Pasii executati de mecanismul de optimizare sunt:
1) Generarea unui set de planuri pentru interogare bazate pe caile de acces la date.
2) Estimarea a cate un cost pentru fiecare plan generat, cost bazat pe statisticile din
dictionarul de date pentru distribuita datelor si caracteristicile de stocare pentru tabelele
si indexii referiti de interogare. Costul este o valoare estimata proportionala cu numarul
de resurse necesare pentru a executa instructiunea cu acel plan. Se calculeaza costul
cailor de acces si ordinii de join bazate pe resursele existente in sistem (I/O, CPU,
RAM). Planurile de executie seriala ce au un cost mai mare vor lua mai mult timp pentru
executie decat cele ce au un cost mai redus.
3) Mecanismul de optimizare compara costurile planurilor si il alege pe cel mai redus.

3. Plan de executie al unei instructiuni.

Planul de executie a unei interogari este compus din blocuri mai mici numite surse de linii
pentru executia seriala a planurilor. Combinatia acestor surse de linii („row sources”) se numeste plan
de executie. Folosind relatia parinte-copil, planul de executie poate fi afisat in format arborescent
(„tree”). Pentru a executa o instructiune SQL, serverul Oracle trebuie sa execute mai multi pasi.
Fiecare pas fie extrage linii de date fizice din baza de date, fie le prepara in vederea extragerii.
Combinatia de pasi pe care serverul ii executa pentru o interogare se numeste planul de
executie. Acesta include o cale de acces pentru fiecare tabel referit si o clasificare a tabelelor de
join, impreuna cu metoda de join specifica.
Planurile de executie ale unei interogari se pot vizualiza in urmatoarele view-uri:
plan_table, v$sql_plan, v$sql_plan_monitor.
Planul de executie al unei interogari se poate analiza folosind comanda EXPLAIN PLAN.
Cand se lanseaza interogarea, mecanismul de optimizare alege un plan de executie si si
insereaza datele care descriu acest plan intr-un tabel.
Comanda EXPLAIN_PLAN nu executa instructiunea SQL, ci doar genereaza planul de
executie folosit de optimizator.

4. Interpretarea unui plan de executie

Planul de executie este o reprezentare a unui arbore de linii de date. Fiecare pas (linie in planul
de executie sau nod in arbore) reprezinta o linie de date. Pentru a citi un plan de executie acesta trebuie
convertit intr-un graf cu o structura arborescenta. Acest lucru se face automat de instrumente ca SQL
Developer.
Modul de interpretare a unui plan de executie:

5
1) Se porneste de sus.
2) Se identifica linia de pornire pentru executie ca fiind prima linie care produce date dar nu
consuma date.
3) In pasul urmator se executa liniile de pe acelasi nivel cu linia anterioara executata.
4) Dupa ce sunt executati copii, se executa parintele.
5) Dupa ce se executa copii si parintele, se navigheaza in arbore prin consultarea nodurilor de pe
acelasi nivel cu parintele si copii acestora.
6) Se continua navigarea pana toate liniile sunt executate.

Daca se ia in considerare planul de executie ca o structura arborescenta, navigarea se face in


felul urmator:
1) Se porneste de la radacina.
2) Se navigheaza pana se ajunge la nodul cel mai din stanga, care se executa primul.
3) Se iau in considerare nodurile (liniile de date) de pe acelasi nivel si se executa.
4) Dupa executia copiilor se executa parintele.
5) Se navigheaza in arbore, luand in considerare nodurile de pe acelasi nivel cu parintele.
6) Se navigheaza si in restul arborelui pana se executa toate nodurile.

Prin analizarea unui plan de executie al unei interogari se urmaresc urmatoarele obiective:
- Sa se execute prima data selectul pe tabela cu filtrul cel mai selectiv
- In acest prim pas se returneaza un numar cat mai mic de linii care apoi sa fie folosite in
eventuale join-uri
- View-urile sunt utilizate corect
- Sa nu fie produse carteziene nedorite
- Tabelele sa fie accesate eficient

6
5. Operatorii optimizatorului.

O sursa de date („row source”) reprezinta un set de linii returnate intr-un pas al unui plan de
executie al unei interogari. Acestea pot fi clasificate astfel:
- Operatori unari: au doar o singura intrare, cum ar fi caile de acces la date
- Operatori binari: au doua intrari, cum ar fi join-urile
- Operatori n-ari: au mai multe intrari, cum ar fi operatorii relationali.
Orice linie dintr-o tabela poate fi identificata prin una din urmatoarele metode:

De obicei, atunci cand interogarea intoarce un set restrans de linii se alege un mod de acces
indexat. Atunci cand se returneaza un numar mare de linii (in comparatie cu numarul total de linii din
tabel), optimizatorul alege un mod de acces de tip „full table”. Optimizatorul alege solutia optima pe
baza unui cost, fiind executata solutia avand costul cel mai mic.
Atunci cand o interogare extrage date din mai multe tabele se folosesc metode de join intre
acestea. Un join:
- Defineste o relatie intre doua surse de date
- Este o metoda de a combina date intre doua surse de date
- Este controlat de predicatele de join, care definesc cum sunt obiectele relationate.

Metodele de join folosite de optimizator sunt:


- bucle imbricate („nested loops”)
- join de tip sort-merge („sorte merge join”)
- joinuri hash („hash joins”)

Nested loops join:


- Tabelul de baza (sursa de baza) este scanat
- Fiecare linie returnata genereaza o cautare in cealalta sursa de date
- Liniile care se potrivesc („joining rows”) sunt returnate

7
Sort merge join:
- Primele doua surse de date sunt sortate dupa aceeasi cheie
- Liniile sortate din cele doua tabele sunt unite („merged”)

Hash join:
- Tabela cea mai mica este folosita pentru a construi o tabela hash
- Liniile din cea de a doua tabela sunt verificate cu tabela hash

Cartesian join este cea mai costisitoare metoda de returnare a liniilor din doua tabele prin executia
unui produs cartezian.

8
6. Exemplul unui plan de executie al unei interogari.

Pentru a executa o instructiune SQL, serverul Oracle trebuie sa execute mai multi pasi.
Fiecare pas fie extrage linii de date fizice din baza de date, fie le prepara in vederea extragerii.
Combinatia de pasi pe care serverul ii executa pentru o interogare se numeste planul de
executie. Acesta include o cale de acces pentru fiecare tabel referit si o clasificare a tabelelor de
join, impreuna cu metoda de join specifica.

Planul de executie a unei interogari se poate analiza folosind comanda EXPLAIN PLAN.
Cand se lanseaza interogarea, mecanismul de optimizare alege un plan de executie si si
insereaza datele care descriu acest plan intr-un tabel.

Exemplu:

EXPLAIN PLAN FOR


SELECT e.empno, e.ename, e.job, e.sal, d.dname, d.loc
FROM emp e, dept d
WHERE e.deptno = d.deptno and e.sal < 2200;

select plan_table_output from


table(dbms_xplan.display('plan_table',null,'serial'));

9
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2862617143
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |Cost(%CPU)
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 225 | 3
| 1 | NESTED LOOPS | | 5 | 225 | 3
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 125 | 2
|* 3 | INDEX RANGE SCAN | IDXEMP_SALCOMM | 5 | | 1
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1
|* 5 | INDEX UNIQUE SCAN | DEPT_PRIMARY_KEY | 1 | | 0
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."SAL"<2200)
5 - access("E"."DEPTNO"="D"."DEPTNO")

Fiecare linie din tabela de iesire corespunde unui pas in planul de executie. Pasii notati cu *
sunt afisati si in sectiunea de informatii despre predicate. Fiecare pas returneaza un set de linii
care este folosit in pasul urmator sau, la ultimul pas, este returnat utilizatorului. Valorile din
coloana Id corespund cu ordinea in care sunt afisati pasii executati. Fiecate pas extrage linii din
tabele sau accepta linii din pasii anteriori.
Pasii urmatori extrag date din baza de date:
- pasul 3 extrage valorile de rowid pentru liniile din EMP pe baza indexului de tip range
- pasul 2 extrage liniile din EMP pe baza informatiilor de rowid extrase la pasul 3
- pasul 5 scaneaza tabela DEPT pe baza indexului creat de cheia primara si extrage
valorile rowid corespunzatoare pe baza relatiei de join
- pasul 4 extrage liniile din DEPT pe baza valorilor de rowid extrase la pasul 5
- pasul 3 combina seturile de rezultate extrase la pasii 2 si 4 pentru a compune rezultatul
prezentat la utilizator

7. Exercitii. ==> Conectarea la BD se face cu user/parola = dwxx/dwxx, xx=nr statiei

1) Testati exemplele din cadrul laboratorului.

2) Afisati produsele comandate in lunile de vara ale anului 1986. Se vor afisa informatiile din
comanda, numele clientului, orasul, statul si limita de credit, numele agentului si numele
departamentului din care face parte, precum si liniile de detaliu (numele produsului, cantitate,
pretul si valoarea). Executati interogarea si afisati planul de executie al interogarii. Analizati
acest plan. Creati indexii necesari pentru a optimiza acest plan de executie

1
3) La interogarea anterioara filtrati liniile de comanda care au valoare mai mare decat 400,
unde valoarea se calculeaza ca produs intre cantitate si pret. Creati un index corespunzator
pentru optimizarea accesului. Afisati si analizati planul de executie al interogarii.

4) Analizati planurile de executie ale urmatoarelor interogari. Creati indexii necesari pentru a
optimiza aceste planuri de executie. Comparati planurile de executie inainte si dupa crearea
indexilor.
SELECT ename, job, sal, dname
FROM emp, dept
WHERE dept.deptno = emp.deptno
and not exists
(select * from salgrade where emp.sal between losal and hisal);

select ename, e.deptno, d.deptno, d.dname


from emp e, dept d
where e.deptno = d.deptno and ename like 'A%';

select /*+ USE_HASH(E D) */ ename, e.deptno, d.deptno, d.dname


from emp e, dept d
where e.deptno = d.deptno and ename like 'A%';

select /*+ USE_MERGE(E D) */ ename, e.deptno, d.deptno, d.dname


from emp e, dept d
where e.deptno = d.deptno and ename like 'A%';

SELECT COUNT(*)
FROM products p
WHERE prod_list_price < 1.15 * (SELECT avg(unit_cost)
FROM costs c
WHERE c.prod_id = p.prod_id);

SELECT COUNT(*)
FROM products p, (SELECT prod_id, AVG(unit_cost) ac FROM costs GROUP BY
prod_id) c
WHERE p.prod_id = c.prod_id AND
p.prod_list_price < 1.15 * c.ac;

SELECT c.cust_first_name, c.cust_last_name, c.cust_id, COUNT(s.prod_id)


FROM sh.customers c, sh.sales s
where c.cust_id = s.cust_id
and c.cust_id < 100
GROUP BY c.cust_first_name, c.cust_last_name, c.cust_id;

SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc,


SUM(s.amount_sold) sales_amount
FROM sh.sales s,sh.times t,sh.customers c,sh.channels ch
WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id AND
s.channel_id = ch.channel_id
AND c.cust_state_province = 'CA' AND ch.channel_desc IN
('Internet','Catalog')
AND t.calendar_quarter_desc IN ('1999-Q1','1999-Q2')
GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc;

11

S-ar putea să vă placă și