Sunteți pe pagina 1din 9

Indexi in Oracle

Obiective
- Insusirea notiunii de index.
- Tipuri de indexi:
- Simpli, compusi
- Bazati pe functii;
- B-Tree, Bitmap;
- Gestiunea indexilor.

1. Notiunea de index.

Indexul este un obiect al bazei de date creat cu scopul de a imbunatati regasirea


informatiilor in tabele. Un index furnizeaza acces direct la inregistrarile din tabela. Scopul
utilizarii indexilor este reducerea numarului de citiri/scrieri pe disc, prin folosirea unor cai
indexate pentru regasirea informatiilor.
Un index poate fi creat in doua moduri:
- automat de server: pentru constrangerile de tip PRIMARY KEY si UNIQUE KEY
- manual de utilizatori printr-o instructiune SQL
Indexul este folosit automat de serverul Oracle la instructiunile SQL lansate de utilizator, in
mod transparent fata de utilizator. Serverul gestioneaza automat indexii cand datele sunt
modificate sau adaugate in tabela. Prezenta a numerosi indexi poate deteriora performantele
operatiilr insert/update/delete pe o tabela.
Indexul este un obiect independent fata de tabela pe care o indexeza, necesita spatiu de
stocare propriu, pot fi creati sau stersi in mod autonom. Daca un tabel este sters atunci sunt
stersi si indexii asociati acelui tabel.
Indexii nu afecteaza modul de scriere a interogarilor, doar viteza de executie a acestora.
Interogarea pe o tabela indexata pointeaza direct spre locatia rindurilor ce contin valorile dorite.
Indexii si cheile sunt doua concepte diferite in Oracle. Indexii sunt obiecte independente ale
bazei de date, pe cand cheile sunt concepte logice pentru implementarea constrangerilor de
integritate si regulilor de afaceri („business rules”) ale domeniului de implementat. Unele chei
(primare si unice) definesc in mod transparent si indexi (unici).
Intr-un index valorile NULL sunt considerate distincte, cu exceptia cazului cand valorile ne-
nule din doua sau mai multe linii sunt identice. Cu exceptia unui index bitmap, serverul nu
indexeaza liniile care au toate valorile din chei NULL.
Se pot crea mai multe tipuri de indexi in Oracle:
- indexi normali, simpli sau compursi, stocati de server sub forma unor structuri B-Tree;
- indexi bitmap, folositi mai ales in depozitele de date;
- indexi partitionati pentru tabelele partitionate
- indexi bazati pe functii Oracle sau utilizator

1
Sintaxa generala de creare a unui index.

Crearea unui index se face cu urmatoarea sintaxa generala.

Sintaxa generala:

Fig.1. Sintaxa instructiunii de creare a unui index.

CREATE INDEX {schema.}index_name ON {schema.}table (col [,col]..)

Index_name – numele indexului creat


Table – numele tabelului pentru care se creaza indexul
Col – numele coloanei sau coloanelor dupa care se indexeaza tabela

Exista clauze diferite pentru diverse tipuri de indexi: normali („table_index_clause”), bitmap,
cluster.

Cand se creaza un index, serverul aloca automat un segment de index in tablespace-ul de index
pentru a stoca datele. Tablespace-ul pentru index este fie cel predefinit pentru proprietar, fie cel
numit explicit in comanda CREATE INDEX. Acesta poate fi unul diferit fata de cel al tabelei
asociate. Pentru obtinerea performantelor optime se recomanda ca tabela si indexul asociat sa
fie stocati in tablespace-uri diferite.

Exemplu:
CREATE INDEX idxemp_ename ON emp(ename);

Pentru crearea indexului idxemp_ename serverul Oracle face urmatoarele operatii:


- sorteaza tabela EMP dupa coloana ename;
- incarca valorile ordonate dupa index impreuna cu rowid-ul corespunzator;
- cand se foloseste o anumita valoare indexata, se face cautarea in lista ordonata, se
extrage rowid-ul si se localizeaza inregistrarea dorita pe baza acestei valori.

Pentru stocarea indexilor normali, serverul Oracle foloseste structuri B-Tree. Acestea sunt
niste arbori echilibrati.
Fara indexare, cautarea unei valori intr-o lista de n linii, parcurge un numar mediu de n/2
linii, valoarea critica daca n creste foarte mult. Daca aceeasi lista de n linii se stocheaza intr-un
arbore de valori ordonate, atunci se parcurg log(n) linii, ceea ce imbunatateste timpul de
cautare.

2
Exista doua tipuri blocuri:
- Ramuri (‘branch blocks’): date stocate pentru cautare, pointeaza catre frunze
- Frunze (‘leaf blocks’): stocheaza perechi de valori si rowid

Fig.2. Stocarea unui index normal intr-o structura B-Tree.

Blocuri de tip ramura (‘branch blocks’):


 Stocheaza prefixul minim al cheii necesar pentru a lua o decizie intre 2 chei
 Pointeaza spre blocul frunza care contine cheia.

Blocuri de tip frunza (‘leaf blocks’):


 Contine valoarea completa a cheii de indexare pentru fiecare linie
 Contine valoarea rowid pentru fiecare linie
 Fiecare pereche (valoare cheie, rowid) pointeaza spre vecinii din stanga si dreapta
 Sortarea este facuta dupa perechea (valoare cheie, rowid)

Avantajele folosirii structurii B-Tree:


 Toate blocurile frunza sunt la aceeasi adancime, deci extragerea oricarei
inregistrari va consuma acelasi timp.
 Indexii B-Tree sunt echilibrati automat
 Toate blocurile din B-Tree sunt in medie pe 3 sferturi ocupate.
 Ofera performante bune pentru o paleta larga de inteorgari: egalitate de valori,
interval de valori, cautare partiala.
 Operatiile DML sunt eficiente, mentinand si ordinea de indexare in B-Tree.
 Performantele indexilor B-Tree sunt bune atat pentru tabele mici cat si pentru
tabele mari.

3
2. Indexi normali, simpli sau compusi, unici, ne-unici, bazati pe functii.

Indexii trebuie creati si pot duce la imbunatatirea timpului de raspuns la interogari doar
in anumite conditii:
- coloana de indexare este utilizata des in clauza WHERE pentru join-uri sau pentru filtre;
- tabela contine multe inregistrari (de la cateva mii in sus);
- rezultatul interogarilor aduce in jur de 10% din continutul tabelelor;
- coloanele de indexare contin o paleta larga de valori si pot contine valori NULL;

3.1 Index normal, simplu, unic.


Se creaza pe o tabela pe o coloana cu valori unice. Este cea mai eficienta metoda de acces la
date. Serverul alege o parcurgere unica a arborelui B-tree atunci cand valorile sunt specificate
prin conditii de egalitate.
Exemplu: Index unic pe coloana ename din tabela EMP.

CREATE UNIQUE INDEX idxemp_ename ON emp(ename);


Interogare pentru care este folosit indexul:
SELECT * FROM emp WHERE ename = ‘MARTIN’;

Pasii pentru scanarea indexilor unici:


1) Se incepe cu blocul radacina.
2) Se cauta blocurile cheie pentru cea mai mica cheie mai mare sau egala cu valoarea
cautata (‘MARTIN’).
3) Daca valoarea cheii este mai mare decat valoarea cautata, atunci se urmeaza ramura
dinainte pentru blocul copil.
4) Daca, cheie = valoarea, atunci se urmeaza ramura pentru blocul copil.
5) Daca in pasul 2) nu se gaseste nici o cheie mai mare sau egala cu valoarea, atunci se
urmeaza calea de dupa cea mai mare cheie din bloc.
6) Atat timp cat blocul copil este o ramura si nu frunza, se repeta pasii de la 2) la 4).
7) Se cauta blocul frunza cu valoarea data.
8) Daca se gaseste se returneaza ROWID.

9) Daca nici o cheie nu e gasita inseamna ca randul nu exista.

4
3.2 Index normal, simplu, ne-unic.
Se creaza pe o tabela pe o coloana cu valori ne-unice.
- pentru coloanele din conditia de join:
CREATE INDEX idxemp_deptno ON emp(deptno);
Serverul foloseste indexul pentru interogari de tipul:
SELECT * from emp e, dept d WHERE e.deptno = d.deptno;

- pentru coloane de filtrare din clauza WHERE:


CREATE INDEX idxemp_hiredate ON emp(hiredate);
Serverul foloseste indexul pentru interogari de tipul:
SELECT * from emp WHERE hiredate
BETWEEN to_date(‘20/02/1981’,’DD/MM/YYYY’) AND
to_date(‘20/02/1982’,’DD/MM/YYYY’)

Pasii pentru scanarea indexilor ne-unici pentru un interval de valori:


1) Se incepe cu blocul radacina.
2) Se cauta blocurile cheie pentru cea mai mica cheie mai mare sau egala cu valoarea de
start (‘20/02/1981’).
3) Daca valoarea cheii este mai mare decat valoarea de start, atunci se urmeaza ramura
dinainte pentru blocul copil.
4) Daca, cheie = valoarea de start, atunci se urmeaza ramura pentru blocul copil.
5) Daca in pasul 2) nu se gaseste nici o cheie mai mare sau egala cu valoarea de start,
atunci se urmeaza calea de dupa cea mai mare cheie din bloc.
6) Atat timp cat blocul copil este o ramura si nu frunza, se repeta pasii de la 2) la 4).
7) Se cauta blocul frunza cu cea mai mica cheie mai mare sau egala cu valoarea de start.

8) Atat timp cat cheia gasita <= valoarea de stop (‘20/02/1982’) se executa:

a. Daca, coloanele cheie indeplinesc toate conditiile din WHERE atunci se


returneaza perechile (valoare, ROWID)
b. Se urmeaza legatura din dreapta
Aici serverul foloseste legaturile intre nodurile frunza pentru a returna rezultatul mai
rapid. In pasul 7) se aplica toate conditiile de filtru pentru coloanele index inainte de a accesa
ROWID.
5
3.3 Index normal, concatenat.
Se creaza atunci cand doua sau mai multe coloane sunt utilizate impreuna in majoritatea
interogarilor pe tabele mari.

CREATE INDEX idxemp_salcomm ON emp(sal,comm);


Serverul foloseste indexul pentru interogari de tipul:
SELECT * from emp WHERE sal < 1500 and comm IS NOT NULL;

3.4 Index normal bazat pe functie.


Au la baza o expresie sau o functie care implica una sau mai multe coloane din tabela
indexata. Indexul calculeaza valoarea functiei sau expresiei si o stocheaza intern. Functia
utilizata poate fi: expresie aritmetica, expresie ce contine functii PL/SQL, functii impachetate,
functii SQL.
Expresiile nu pot contine functii agregat si trebuie sa fie determinate. Nu se pot construi pe
baza coloanelor de tip LOB, REG sau coloane nested.
De obicei, acest tip de index se foloseste la cautari lexicografice de tip „case insensitive”.

CREATE INDEX idxemp_upperemp ON emp(UPPER(ename));


Serverul foloseste indexul pentru interogari de tipul:
SELECT * from emp WHERE UPPER(ename) like ‘%LL%’;

3. Indexi de tip bitmap.

Scopul unui index este de a furniza pointeri spre liniile din tabel pentru valorile date.
Pentru indexii normali acest lucru este implementat prin structuri arborescente de tip B-tree.
Un index normal stocheaza, pe langa valoarea cheii si o lista de rowid-uri pentru acea cheie,
cu scopul de a localiza liniile corespunzatoare.
In depozitele de date cu tabele de tip „fact” cu foarte multe inregistrari se folosesc
indexii bitmap. Acest lucru este necesar deoarece o structura de tip B-tree ar fi foarte
costisitoare ca spatiu de stocare si timp de parcurgere pentru un volum mare de date.
La un index bitmap pentru fiecare cheie se stocheaza un harta de biti (bitmap) in loc de
lista de rowid-uri. Fiecare bit din harta corespunde cu un posibil rowid. Daca bitul este setat
atunci linia cu rowid-ul corespunzator contine valoarea cheie. O functie de mapare
converteste pozitia bitului in rowid-ul liniei. Daca numarul de valori de cheie diferite este
mic, atunci spatiul de stocare este redus dramatic.
Indexarea de tip bitmap combina indexii care corespund cu diverse conditii din clauza
WHERE. Liniile care nu indeplinesc toate conditiile de filtrare sunt eliminate, castigandu-se
timp de raspuns.
6
Cardinalitatea unei coloane este data de numarul de valori distincte in comparatie cu
numarul total de linii. Astfel, daca avem un tabel cu un milion de inregistrari si o coloana
are 10 mii de valori distincte posibile, atunci acea coloana are cardinalitate mica si este un
candidat pentru un index de tip bitmap.
Coloanele cu cardinalitate mare sunt candidate pentru indexii normali stocati in arbori de
tip B-tree.
Indexii de tip bitmap pot imbunatati substantial performantele interogarilor ad-hoc ce
includ expresii avand coloane de cardinalitate redusa in clauza WHERE, coloane conectate
cu operatori AND, OR. Daca numarul de linii intoarse este mic nu este necesara o scanare
completa a tabelei, interogarea avand un timp de raspuns foarte mic.
Se considera tabela CUSTOMERS din schema SH cu o interogare de tipul:
SELECT cust_id, cust_gender, cust_marital_status, cust_income_level
FROM customers;

Coloanele cust_gender, cust_marital_status si cust_income_level sunt coloanele de


cardinalitate redusa, deci candidate pentru un index de tip bitmap.

Un index de tip bitmap se creaza cu urmatoarea instructiune:

CREATE BITMAP INDEX custidx_gender ON customers (cust_gender);


CREATE BITMAP INDEX custidx_marital ON customers
(cust_marital_status);
CREATE BITMAP INDEX custidx_income ON customers (cust_income_level);

Fiecare intrare in harta de biti corespunde unei linii din tabel. De exemplu, liniile cu
marital_status=’divorced’ au in harta 1 pe coloana respectiva.
Indexii de tip bitmap creati sunt folosit la o interogare de tipul: „Cati clienti casatoriti au
nivelul de venituri de tipul G sau H ?”

SELECT COUNT(*) FROM customers


WHERE cust_marital_status = 'married'
AND cust_income_level IN ('H: 150,000 - 169,999',
'G: 130,000 - 149,999');

7
Indexii de tip bitmap proceseaza eficient acest tip de interogare prin folosirea hartii de biti
ca in figura urmatoare:

Avantajele folosirii indexilor de tip bitmap intr-un depozit de date:


 Reduce timpul de raspuns pentru o clasa larga de interogari ce folosesc coloane
de cardinalitate redusa.
 Reduce spatiul de stocare comparativ cu alte tehnici de indexare.
 Creste performantele chiar si pentru configuratii hardware slabe.
 Foarte eficient pentru operatii DML paralele sau pentru incarcari masive de date.

4. Gestionarea indexilor.

Un index se poate modifica sau sterge fara a influenta datele din tabela de baza sau
continutul interogarilor deja create. La stergerea unei tabele toti indexii asociati sunt stersi
automat.
Modificarea parametrilor unui index se executa cu instructiunea ALTER INDEX.

Stergerea unui index se face cu instructiunea DROP INDEX:

DROP INDEX idx_name;

Exemplu:

DROP INDEX idxemp_deptno;

Indexii creati se pot vizualiza in doua view-uri de dictionar: USER_INDEXES si


USER_IND_INDEXES.

SELECT * FROM USER_INDEXES idx, USER_IND_COLUMNS idxc


WHERE idx.index_name = idxc.index_name

8
5. Exercitii.

1) Testati exemplele din cadrul laboratorului.

2) Se dau tabelele PRODUCT, CUSTOMER, ORD, ITEM. Creati urmatorii indexi:


- pentru tabela CUSTOMER:
- creati indexii unici pentru coloana NAME;
- creati indexi simpli, normali pentru CREDITLIMIT si REPID;
- creati un index pe baza de functie care sa optimizeze accesul dupa numele clientului
atunci cand valorile se introduc cu litere mici;
- pentru tabela ORD creati indexii necesari pentru interogarile care implica un join cu tabela de
clienti si care filtreaza liniile dupa data comenzii;

3) 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). Creati indexii necesari si apoi sa-i afisati din dictionarul de date.

4) 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.

5) Pe baza tabelelor PRODUCT, CUSTOMER, ORD, ITEM, creati o tabela fapta (“fact”),
numita ORDITEM care sa contina datele din tabelele ORD si ITEM si care sa aiba coloanele:
custid, prodid, orderdate, commplan, shipdate, qty, actualprice si itemtot. Creati indexi
necesari:
- unic compus pentru client, produs;
- creati un index de tip bitmap pentru coloanele candidate;
- lansati o serie de interogari care sa utilizeze indexii creati;

6) Afisati suma vanzarilor pe primul trimestru al anului 1998 pentru clientii din Europa de vest
si America de sud (tabelele SALES, CUSTOMERS, COUNTRIES, TIMES).
Creati indexii necesari si sa-i afisati din dictionarul de date.

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