Sunteți pe pagina 1din 29

200

Partea l Utilizarea general a sistemului MySQL


WHERE
col_d = expresie
<> o coloan adecvat
Coloanele pe care le selectai si coloanele pe care le folosii n clauza WHERE pot fi ide tice, desigur. Ideea este
c apariia unei coloane n lista de selecie nu reprezint o su| gestie pentru indexarea acesteia.
Coloanele care apar n clauzele de unire sau n expresii de forma coli = co!2 sur extrem de adecvate pentru
indexare. Coloanele col_b i col_c din interogarea prezei tat anterior sunt exemple n acest sens. Dac MySQL
poate optimiza o interog folosind coloane unite, atunci reduce semnificativ posibilele combinaii tabel-rnij prin
eliminarea baleierilor complete ale tabelului.
Folosii indexuri unice. Gndii-v la domeniul de valori al unei coloane. Indexur funcioneaz cel mai bine
pentru coloane cu valori unice, respectiv cel mai slab n < zul coloanelor care prezint numeroase valori
duplicate. De exemplu, dac o coloa conine vrste si are numeroase valori diferite, un index va face imediat
diferena ntr rnduri. Un index nu va fi de mare ajutor dac o coloan este folosit pentru a nreg tra sexul unei
persoane i conine numai cele dou valori "M" si "F" (indiferent de vjjij loarea pe care o cutai, oricum vei
obine cam jumtate din rnduri).
Folosii indexuri scurte. Dac indexai o coloan ir, specificai o lungime a prefixti| lui ori de cte ori situaia
o permite. De exemplu, dac avei o coloan CHAR (200), n<j indexai ntreaga coloan dac primele 10 sau 20
de caractere dintr-o valoare surif| unice. Prin indexarea primelor 10 sau 20 de caractere se va economisi o mare
cantitat de spaiu n fiierul index i probabil c interogrile vor deveni i ele mai rapide. Ul index mai mic
necesit mai puine operaii de intrare-ieire cu discul, iar valorile scurte pot fi comparate mai rapid. Mai
important este c, dac valorile cheilor sunt scurte, blocurile din zona cache a indexului pot conine mai multe
valori ale cheilo^l deci MySQL poate stoca n memorie mai multe chei simultan. Astfel, crete probabili?! tatea
de localizare a rndurilor fr a mai fi necesar citirea de blocuri suplimentai din index. (Dorii s v folosii si
bunul sim, desigur. Indexarea numai a primului racter dintr-o coloan nu este chiar att de util, deoarece n
index nu vor exista multe valori distincte.)
Utilizai prefixele de stnga. Cnd creai un index cu n coloane, de fapt creai indexuri pe care MySQL le poate
folosi. Un index pentru mai multe coloane est echivalent cu mai multe indexuri, deoarece orice set de coloane de
stnga ale indexuri lui se poate folosi pentru stabilirea corespondenei cu anumite rnduri. Un asemene*! set se
numete prefix de stnga1 (n original leftmost prefix - N.T.).
S presupunem c avei un tabel cu un index pentru coloane denumite stat, ora i cod_postal. Rndurile din
index sunt sortate n ordinea stat/oras/cod_postal, de sunt automat sortate att n ordinea stat/ora, ct i n
funcie de stat. Aceast nseamn c MySQL poate beneficia de index chiar daca specificai ntr-o interogare!
numai valorile din coloana stat, respectiv numai valorile din coloanele stat i oras.*| Astfel, indexul poate fi
folosit pentru a cuta urmtoarele combinaii de coloane:
1 Aceast operaie este diferit de indexarea prefixului unei coloane, care folosete primele n caract ale coloanei
pentru valorile din index. - N.A.
Capitolul 4 Optimizarea interogrilor
201
stat, ora, cod_postal
stat, ora
stat
MySQL nu poate folosi indexul pentru cutri care nu implic un prefix de stnga. De exemplu, n cazul n care
cutai n funcie de ora sau cod_postal, indexul nu va fi folosit. Dac suntei n cutarea unui stat dat i al unui
anumit cod postai (coloanele l i 3 ale indexului), indexul nu poate fi folosit pentru combinaia de valori
respectiv. Totui, MySQL poate reduce domeniul de cutare folosind indexul pentru a gsi rndurile care conin
statul cutat.
Nu folosii indexul n mod excesiv. Nu indexai tot ce vedei cu ochii, pornind de la zicala cu ct mai mult, cu
att mai bine". Este o-greeal. Fiecare index suplimentar ocup spaiu pe disc i afecteaz performanele
operaiilor de scriere, aa cum s-a artat deja. Indexurile trebuie actualizate si eventual reorganizate atunci cnd
modificai coninutul tabelelor dumneavoastr, operaie care are o durat direct proporional cu numrul
indexurilor. Dac avei un index care este folosit rareori sau niciodat, diminuai n mod inutil viteza de efectuare
a modificrilor din tabel, n plus, MySQL ia n considerare indexurile atunci cnd genereaz un plan de execuie
pentru regsiri. Crearea de indexuri suplimentare nseamn mai mult munc pentru utilitarul de optimizare a
interogrilor. Este de asemenea posibil (dei improbabil) ca MySQL s nu aleag cel mai bun index pentru
utilizare atunci cnd avei prea multe indexuri. Pstrarea numai a indexurilor de care avei nevoie ajut utilitarul
de optimizare a interogrilor s evite asemenea greeli.
Dac v gndii s adugai un index la un tabel care este deja indexat, gndii-v dac indexul pe care v gndii
s-1 adugai nu este un prefix de stnga al unui index pe mai multe coloane deja existent, n acest caz, nu v
mai deranjai s adugai indexul, deoarece, n realitate, l avei.
inei cont de tipurile de comparaii pe care le efectuai cu valorile dintr-o coloan. Indexurile sunt folosite
pentru operaiile <, <=, =, >=, > i BETWEEN. Indexurile sunt de asemenea folosite pentru operaiile LIKE,

atunci cnd modelul are un prefix literal. Dac folosii o coloan numai pentru alte categorii de operaii, cum ar
fi STRCMP (), nu are nici un sens s o indexai.
Utilitarul de optimizare a interogrilor din MySQL
Cnd emitei o interogare pentru selectarea rndurilor, MySQL o analizeaz pentru a vedea dac poate beneficia
de optimizri care s-i permit s prelucreze interogarea mai rapid, n aceast seciune, vom examina modul de
funcionare al utilitarului de optimizare. Pentru informaii suplimentare, consultai capitolul Obinerea unui
nivel maxim de performan din utilizarea sistemului MySQL" din manualul de referin MySQL. Capitolul
respectiv descrie diferite msuri de optimizare pe care le ia MySQL. La acest capitol sunt adugate ocazional
alte informaii, deoarece dezvoltatorii MySQL continu s mbunteasc utilitarul de optimizare, deci merit s
recitii capitolul din cnd n cnd, pentru a vedea dac n-au aprut ponturi noi pe care s le utilizai. (Versiunea
electronic a manualului MySQL, de la adresa http://www.mysql.com/, este n permanen actualizai)
-'. '*!*.Xj3 i ,^*-*5*
202
Partea l Utilizarea general a sistemului MySQL
Utilitarul de optimizare a interogrilor din MySQL utilizeaz indexurile, desigur, da folosete i alte informaii.
De exemplu, dac emitei urmtoarea interogare, MySQL l va executa foarte rapid, indiferent de dimensiunea
tabelului:
SELECT * FROM numejtabel WHERE 1 = O n acest caz, MySQL examineaz clauza WHERE, sesizeaz c
nici un rnd nu poate satis face interogarea i nici mcar nu se mai obosete s caute n tabel. Putei vedea acest
luc cu ajutorul instruciunii EXPLAIN, care cere sistemului MySQL s afieze unele informat despre modul n
care ar executa o instruciune SELECT, fr a o executa efectiv. Pent folosi EXPLAIN, pur i simplu inserai
cuvntul EXPLAIN n faa instruciunii SELECT:
EXPLAIN SELECT * FROM nume_tabel WHERE 1 = O Rezultatul instruciunii EXPLAIN este
urmtorul:
Comment
Impossible WHERE
(clauz WHERE imposibila)
n mod normal, EXPLAIN returneaz mai multe informaii dect cea prezentat mai si inclusiv date despre
indexurile care vor fi folosite pentru baleierea tabelelor, tipurile di uniri care vor fi folosite, respectiv estimeaz
numrul de rnduri care vor trebui parcur din fiecare tabel.
Modul de funcionare a utilitarului de optimizare
Utilitarul de optimizare a interogrilor din MySQL are numeroase scopuri, dar prir pala sa menire este de a folosi
indexurile ori de cte ori este posibil, precum si de a folc indexul cel mai restrictiv, pentru a elimina ct mai
multe rnduri ntr-un timp ct scurt. Poate prea ciudat, deoarece, atunci cnd emitei instruciuni SELECT,
scopul du neavoastr este de a gsi rnduri, nu de a le elimina. Motivul pentru care utilitarul optimizare
funcioneaz n acest mod este urmtorul: cu ct pot fi scoase din disc rnduri ntr-o manier mai expeditiv, cu
att pot fi gsite mai rapid rndurile care sais fac criteriile de cutare. Interogrile pot fi prelucrate mai rapid
dac testele cele restrictive se pot efectua primele. S presupunem c avei o interogare care testeaz doii
coloane, ambele coloane fiind dotate cu index:
WHERE coli = "o valoare" AND co!2 = "o alta valoare"
S presupunem c testul aplicat asupra coloanei l gsete 900 de rnduri, c testul aplid asupra coloanei 2 gsete
300 de valori, i c ambele teste reuesc n cazul a 30 de rndi Dac testai mai nti coloana l, trebuie s
examinai 900 de rnduri pentru a le gsi cele 30 care corespund i valorii din coloana 2. Asta nseamn 870 de
teste ratate. Daj testai mai nti coloana 2, trebuie s examinai numai 300 de rnduri pentru a le gsi j cele 30
care de asemenea corespund valorii din coloana 1. Numrul testelor ratate n; caz este de 270, ceea ce implic
mai puine calcule si operaii de intrare-ieire cu disc
Putei ajuta utilitarul de optimizare s foloseasc indexurile folosind urmtoarele ndrur Comparai coloane de
acelai tip. Cnd folosii coloane indexate n comparaii, ut lizai coloane de acelai tip. De exemplu, CHAR (10)
este considerat identic cu CHAR (K sau VARCHAR(IO), dar diferit de CHAR(12) sau VARCHAR(12). INT este
diferit de BIGII*
Capitolul 4 Optimizarea interogrilor
203
Utilizarea coloanelor de acelai tip este o cerin obligatorie n versiunile de MySQL anterioare versiunii 3.23, n
caz contrar indexurile pentru coloane nefiind folosite, ncepnd de la versiunea 3.23, acest lucru nu este strict
necesar, dar tipurile de coloane identice v vor oferi performane superioare tipurilor de coloane diferite, n cazul
n care coloanele pe care le comparai sunt de tipuri diferite, putei folosi ALTER TABLE n scopul de a modifica
unul dintre ele, pentru a obine asemnarea. ncercai s singularizai coloanele indexate n comparaii. Dac
folosii o coloan ntr-un apel la o funcie sau ntr-o expresie aritmetic, MySQL nu poate folosi indexul,
deoarece trebuie s calculeze valoarea expresiei pentru fiecare rnd. Uneori acest lucru este inevitabil, dar de
multe ori putei rescrie o interogare pentru a obine chiar coloana indexat.
Urmtoarele clauze WHERE ilustreaz acest aspect, n prima linie, utilitarul de optimizare va simplifica expresia
4/2 la valoarea 2, apoi va folosi un index pe coloanajnea pentru a descoperi rapid valorile mai mici dect 2. n a

doua expresie, MySQL trebuie s regseasc valoarea din coloanajnea pentru fiecare rnd, s multiplice cu 2 i
apoi s compare rezultatul cu 4. Nu se poate folosi nici un index, deoarece trebuie regsit fiecare valoare din
coloan, astfel nct expresia din membrul stng al comparaiei s poat fi evaluat:
WHERE coloanajnea < 4 / 2
WHERE coloanajnea * 2 < 4
S ne gndim la un alt exemplu. S presupunem c avei o coloan indexat data_col. Dac emitei o interogare
precum urmtoarea, indexul nu este folosit:
SELECT * FROM tabeluljneu WHERE YEAR(data_col) < 1990 Expresia nu compar valoarea dintr-o coloan
indexat cu 1990; se compar o valoare calculat din valoarea coloanei, iar valoarea respectiv trebuie calculat
pentru fiecare rnd. Ca rezultat, indexul pe coloana data_col nu poate fi folosit. Care este remediul? Folosii o
datS literal, i indexul pentru coloana data j;ol va fi utilizat:
WHERE data_col < "1990-01-01"
Dar s presupunem c nu avei o dat precizat, n schimb, suntei interesat n gsirea nregistrrilor a cror dat
se afl la un anumit numr de zile de data de astzi. Exist numeroase metode de scriere a unei interogri precum
aceasta, dar nu toate la fel de bune. Sunt trei posibiliti:
WHERE TO_DAYS(data_COl) - TOJ)AYS(CURRENT_DATE) < limita
WHERE TO_DAYS(data_col) < limita + TOJ)AYS(CURRENTJ)ATE)
WHERE data_COl < DATE_ADD(CURRENTJ)ATE, INTERVAL limita DAY) Pentru prima linie, nu va fi
folosit nici un index, deoarece coloana trebuie regsit pentru fiecare rnd, pentru a permite calculul valorii
TOJ)AYS(dataj3ol). A doua linie este mai bun. Att limita ct si TO_DAYS(CURRENT_DATE)sunt constante,
deci membrul drept al comparaiei poate fi calculat o singur dat de utilitarul de optimizare nainte de
prelucrarea interogrii nu pentru fiecare rnd n parte. Dar coloana data_col apare ntr-un apel la o funcie, deci
indexul nu este folosit. Cea de-a treia linie este metoda ideal. Din nou, membrul drept al comparaiei poate fi
calculat o singura dat, fiind o constant, naintea execuiei interogrii, dar acum valoarea este o
204
Partea l Utilizarea general a sistemului MySQL
dat calendaristic. Acea valoare poate fi comparat direct cu valorile din coloaiS data_col, care nu mai trebuie
convertite n zile. n acest caz, se poate folosi index
Nu folosii caractere de nlocuire la nceputul unui model LIKE. Uneori oamerjj caut iruri folosind o clauz
WHERE de forma urmtoare:
WHERE nume_coloana LIKE "%sirV Aceasta este o operaie corect dac dorii s gsii irul ir indiferent
unde apli acesta n interiorul coloanei. Dar nu inserai caracterul % de ambele pri doar d obinuin. Dac ntradevr cutai irul numai atunci cnd acesta apare la nceput coloanei, atunci nu mai scriei primul caracter %.
De exemplu, n cazul n care caut ntr-o coloan care conine nume de familie acele nume care ncep cu "Mac",
ser clauza WHERE astfel:
WHERE nume LIKE "Mac%" Utilitarul de optimizare examineaz partea literal iniial a modelului i folosii
indexul pentru a gsi rndurile care corespund acestuia, ca si cum ai fi scris urni toarea expresie, care se afl
ntr-o form ce permite utilizarea unui index peni coloana nume:
WHERE nume >= "Mac" AND nume < "Mad"
Aceast optimizare nu se aplic operaiilor de stabilire a corespondenelor cu model care folosesc operatorul
REGEXP.
Ajutai utilitarul de optimizare s efectueze estimri mai bune ale eficienei inde
lui. n mod prestabilit, cnd comparai valorile din coloanele indexate cu o const utilitarul de optimizare va
presupune c valorile cheilor sunt distribuite n mod unifot' n index. De asemenea, utilitarul de optimizare va
verifica rapid indexul, pentru a estifl numrul de intrri din index care vor fi folosite atunci cnd se determin
dac indexul 1 buie folosit sau nu pentru comparaiile cu valori constante. Putei furniza utilitaruluil optimizare
informaii mai bune folosind opiunea - -analyze cu myisamchk sau isa pentru a analiza distribuia valorilor
cheilbr. Folosii myisamchk pentru tabele respectiv isamchk pentru tabele ISAM. Pentru a efectua analiza
cheilor, trebuie s ] deschide o sesiune de lucru la gazda serverului MySQL si trebuie s avei acces de i la
fiierele tabelului.
Utilizai instruciunea EXPLAIN pentru a verifica funcionarea utilitarului de < mizare. Verificai dac n
interogrile dumneavoastr sunt folosite indexurile pe eliminarea cu rapiditate a rndurilor. Dac nu, putei
ncerca s folosii STRAIGHT_J pentru a fora efectuarea unei uniri folosind tabele ntr-o anumit ordine,
interogarea n diferite moduri pentru a v forma o opinie; s-ar putea ca MySQIi| aib un motiv solid pentru a nu
folosi indexurile n ordinea pe care dumneavoast considerai cea mai bun.
Testai forme alternative ale interogrilor, dar rulai-le de mai multe ori. Cnd l tai formele alternative ale unei
interogri, rulai-le de mai multe ori n fiecare fc Dac rulai ambele variante ale unei interogri cte o singur
dat pe fiecare,' $ descoperi frecvent c a doua variant este mai rapid, i aceasta numai deoarece ir maiile de la
prima interogare se afl nc n zona cache a discului i nu trebuie efectiv citite de pe disc. De asemenea, trebuie
s ncercai s rulai interogrile at
Capitolul 4 Optimizarea interogrilor
205

cnd ncrcarea sistemului este relativ stabil, pentru a evita efectele datorate altor activiti din sistemul
dumneavoastr.
Anularea efectelor optimizrii
Poate prea ciudat, dar exist situaii cnd dorii s contracarai tehnicile de optimizare ale sistemului MySQL.
Unele din aceste circumstane sunt descrise n seciunea de fa:
Pentru a fora sistemul MySQL s tearg ncet coninutul unui tabel. Cnd dorii s tergei complet coninutul
unui tabel, acesta poate disprea cel mai repede dac se folosete o instruciune DELETE fr nici o clauz
WHERE:
DELETE FROM nume_tabel
MySQL optimizeaz acest caz special de instruciune DELETE; pur i simplu re-creeaz fiiere de date i fiiere
index vide pornind de la zero, folosind, descrierea tabelului din fiierul cu informaii privind tabelul. Aceast
optimizare mrete extrem de mult viteza operaiei de tergere, deoarece MySQL nu mai trebuie s tearg
fiecare rnd n parte. Totui, operaia are unele efecte care nu sunt de dorit n anumite circumstane:
MySQL raporteaz numrul rndurilor afectate de instruciune ca fiind zero, chiar dac tabelul nu era vid. n
majoritatea cazurilor, acest aspect nu conteaz (dei poate fi derutant dac nu v ateptai la aa ceva), dar pentru
aplicaii care au efectiv nevoie s cunoasc numrul real de rnduri, aceast opiune nu este adecvat.
Dac tabelul conine o coloan AUTO_INCREMENT, numerotarea secvenei din coloan este reiniializat
pentru a ncepe de la 1. Acest lucru este adevrat chiar i n condiiile mbuntirii metodelor de manipulare a
atributului AUTO_INCREMENT, introduse n MySQL versiunea 3.23 i expuse n seciunea Lucrul cu
secvene" a capitolului 2, Lucrul cu date n MySQL".
Putei deoptimiza" o instruciune DELETE adugnd o clauz WHERE 1>0: DELETE FROM nume_tabel
WHERE 1 > O
Aceast instruciune foreaz sistemul MySQL s execute o tergere rnd cu rnd. Interogarea se execut mult
mai lent, dar va returna numrul real de rnduri terse. De asemenea, va conserva numerotarea curent a
secvenei AuTO_INCREMENT, dei numai pentru tabelele MylSAM (disponibile n MySQL versiunea 3.23 i
n versiunile ulterioare). Pentru tabelele ISAM, din pcate, secvena este totui reiniializat.
* Pentru a evita un ciclu de actualizare infinit. Dac actualizai o coloan indexat, este posibil ca rndurile care
sunt actualizate s fie actualizate la infinit, n cazul n care coloana este folosit n clauza WHERE i cnd
actualizarea mut valoarea indexului n partea din domeniu care nu a fost nc prelucrat. S presupunem c
tabelul tabeluljneu are o coloan ntreag col_cheie care este indexat. Interogri ca urmtoarea pot cauza
probleme:
UPDATE tabeluljneu SET col_cheie = col_cheie+1
WHERE col_cheie > 0;
Soluia n acest caz este utilizarea coloanei col_cheie ntr-o expresie din clauza WHERE, astfel nct MySQL s
nu poat folosi indexul:
206
Partea l Utilizarea general a sistemului MySQL
UPDATE tabeluljneu SET col_cheie = col_cheie+1
WHERE col_cheie+0 > 0;
De fapt, mai exist o soluie: trecei la versiunea MySQL 3.23.2 sau la o versiune : recent, ceea ce va avea ca
efect remedierea problemei.
Pentru a regsi rezultate ntr-o ordine aleatoare, ncepnd de la versiunea MyS( 3.23.2, putei folosi funcia
ORDER BY RAND() pentru sortarea aleatoare a rezultatel O alt tehnic, util pentru versiuni mai vechi de
MySQL, este de a selecta o coloa de numere aleatoare i de a sorta n funcie de coloana respectiv. Totui, dac
scrii interogarea dup cum urmeaz, utilitarul de optimizare contracareaz intenia dui$ neavoastr:
SELECT ..., RND() AS ratld_col FROM ... ORDER BY rand_COl Problema n acest caz este c
MySQL vede" c respectiva coloan este un apel la j funcie, crede c valoarea coloanei va fi o constant si
optimizeaz clauza ORDER chiar din interogare! Putei induce n eroare utilitarul de optimizare fcnd referirel
interiorul expresiei la o coloan din tabel. De exemplu, dac tabelul dumneavoa are o coloan denumit vrsta,
putei scrie interogarea astfel:
SELECT varsta*0+RAND() AS rand_col
FROM ... ORDER BY rand_col
Pentru a anula ordinea de unire a tabelelor stabilit de utilitarul de optimiza Folosii STRAIGHT_JOIN pentru
a fora utilitarul de optimizare s foloseasc tabele ntr-o anumit ordine. Dac procedai astfel, trebuie s
ordonai tabelele de manier nct primul tabel s fie cel din care va fi selectat cel mai mic numr de ru duri.
(Dac nu suntei sigur care este acest tabel, trecei tabelul cu numrul cel mare de rnduri pe prima poziie din
list.) Cu alte cuvinte, ncercai s ordona tabelele astfel nct selecia cea mai restrictiv s se aplice prima.
Interogrile desfoar mai bine dac putei elimina ct mai rapid rndurile candidate posibile, uitai s ncercai
interogarea n ambele sensuri; pot exista motive pentru care utilit de optimizare nu unete tabelele n modul n
care credei c ar trebui s procedeze, ii instruciunea STRAIGHT_JOIN poate s nu fie de prea mare ajutor.
Alegerea tipurilor de coloan si eficiena interogrilor

Aceast seciune furnizeaz unele instruciuni pentru alegerea coloanelor care pot < tribui la executarea mai
rapid a interogrilor2:
Folosii coloane cu lungime fix, nu coloane cu lungime variabil. Acest lucru valabil mai ales pentru tabelele
care sunt modificate frecvent si care sunt, ca atare, j supuse la fragmentare. De exemplu, transformai toate
coloanele caracter n col CHAR, nu VARCHAR. Compromisul este acela c tabelul dumneavoastr va folosi
mult spaiu, dar, dac v putei permite spaiul suplimentar, rndurile cu lungime i pot fi prelucrate mai rapid
dect rndurile cu lungime variabil.
2 n aceast expunere, prin tipuri BLOB" se vor nelege att tipurile BLOB, ct i tipurile TEXT. - N.A.
Capitolul 4 Optimizarea interogrilor
207
Nu folosii coloane mai lungi atunci cnd se pot utiliza i coloane mai scurte. Dac folosii coloane CHAR de
lungime fix, nu le facei inutil de lungi. Dac valoarea cea mai scurt pe care o stocai ntr-o coloan este de 40
caractere, nu o declarai sub forma CHAR(255); declarai-o sub forma CHAR(40). Dac putei folosi
MEDIUMINT n loc de BIGINT, tabelul dumneavoastr va fi mai mic (ceea ce implic mai puine operaii de
intrare-ieire cu discul), iar valorile vor fi prelucrate mai rapid n cadrul calculelor.
Declarai coloanele ca NOT NULL. Astfel, obinei o vitez de prelucrare mai mare i avei nevoie de un spaiu
de stocare mai redus. De asemenea, va simplifica uneori interogrile, deoarece nu trebuie s tratai NULL ca pe
un caz special.
Luai n calcul utilizarea de coloane ENUM. Dac avei o coloan ir care conine numai un numr limitat de
valori distincte, luai n considerare conversia acesteia la o coloan ENUM. Valorile ENUM pot fi prelucrate
rapid, deoarece sunt reprezentate intern sub form de valori numerice.
Folosii PROCEDURE ANALYSE(). Dac dispunei de MySQL versiunea 3.23 sau de o versiune ulterioar,
rulai funcia PROCEDURE ANALYSE!) pentru a primi informaii despre coloanele din tabelul
dumneavoastr:"
SELECT * FROM nume_tabel PROCEDURE_ANALYSE()
SELECT * FROM nume_tabel PROCEDURE_ANALYSE(16,256)
Una dintre coloanele datelor de ieire este o sugestie a tipului optim de coloan pentru fiecare dintre coloanele
tabelului dumneavoastr. Cel de-al doilea exemplu indic funciei PROCEDURE ANALYSE () s nu sugereze
tipuri ENUM care conin mai mult de 16 valori sau care ocup mai mult de 256 octei (putei modifica valorile
dup cum dorii). Fr asemenea restricii, datele de ieire pot fi foarte lungi; declaraiile ENUM sunt deseori
dificil de citit.
n funcie de datele de ieire ale funciei PROCEDURE ANALYSE O, putei descoperi c tabelul dumneavoastr
poate fi modificat pentru a beneficia de un tip mai eficient. Folosii ALTER TABLE dac dorii s modificai un
tip de coloan.
mpachetai" date ntr-o coloan BLOB. Utilizarea unui tip BLOB pentru a stoca date pe care le mpachetai i
le despachetai n aplicaia dumneavoastr v poate permite s obinei toate datele printr-o singur operaie de
regsire, n loc de mai multe asemenea operaii. Utilizarea tipului BLOB poate fi de asemenea de folos pentru
datele care nu sunt uor de reprezentat ntr-o structur de tabel standard sau care se modific n timp. n
expunerea instruciunii ALTER TABLE din capitolul 3, unul din exemple aborda un tabel folosit pentru stocarea
rezultatelor din cmpurile unui chestionar bazat pe Web. Exemplul respectiv prezenta modul n care putei folosi
instruciunea ALTER TABLE pentru a aduga coloane la tabel ori de cte ori adugai ntrebri la chestionar.
O alt modalitate de abordare a acestei probleme este de a determina programul de aplicaie care prelucreaz
formularul Web s mpacheteze" datele ntr-un fel de structur de date, iar apoi s le insereze ntr-o singur
coloan BLOB. Astfel, aplicaia capt suprasarcina de codificare a datelor (i de decodificare a acestora mai
trziu, atunci cnd regsii nregistrri din tabel), dar se simplific structura tabelului i se elimin necesitatea de
modificare a structurii tabelului atunci cnd chestionarul se modific.
208
Partea l Utilizarea general a sistemului MySQL
Pe de alt parte, valorile BLOB pot provoca propriile lor probleme, mai ales dac ef tuai o mulime de operaii
de tip DELETE i UPDATE. tergerea unui BLOB poate lsa i mare gol n tabel, gol care va fi umplut ulterior
cu o nregistrare sau nregistrri dimensiuni probabil diferite.
Folosii instruciunea OPTIMIZE TABLE pentru tabele supuse la fragment
Tabelele care sufer numeroase modificri, mai ales acelea care conin coloane lungime variabil, sunt supuse
fragmentrii. Fragmentarea nu este indicat, deoar$ duce la apariia unor spaii nedorite n blocurile de pe disc
folosite pentru stoca tabelului dumneavoastr, n timp, trebuie s citii mai multe blocuri pentru a obiijj rndurile
valide, iar performanele sunt diminuate. Acest lucru este adevrat pen orice tabel cu rnduri de lungime
variabil, dar este valabil mai ales pentru coloane BLOB, deoarece dimensiunea acestora poate varia foarte mult.
Utilizarea sistematic i instruciunii OPTIMIZE TABLE contribuie la mpiedicarea degradrii performanele
tabelului.
Folosii un index sintetic. Coloanele unui index sintetic pot fi uneori utile. O tehr este de a crea o valoare hash3
n funcie de alte coloane i de a o stoca ntr-o coloar separat. Apoi, putei gsi rnduri prin cutarea valorilor
hash. Acest procedeu est util numai pentru interogrile care caut corespondene exacte cu un model dat|

(Valorile hash sunt inutile pentru cutri ntr-un domeniu cu operatori precum < sa >=.) Valorile hash pot fi
generate n MySQL 3.23 sau n versiunile ulterioare folosii funcia MD5 ().
Un index hash poate fi deosebit de util n ceea ce privete coloanele BLOB. Unul dii motive este c nu putei
indexa aceste tipuri anterior versiunii MySQL 3.23.2. chiar i n versiunea 3.23.2 sau n versiunile ulterioare,
valorile BLOB pot fi mai uor d| gsit folosind o valoare hash ca identificator dect prin cutarea n coloana
BLOB.
Evitai s regsii valori BLOB sau TEXT prea mari, cu excepia situaiilor cnd suni tei obligat s o facei. De
exemplu, o interogare SELECT * nu este o idee prea bur dect dac suntei sigur c clauza WHERE va limita
rezultatele la rndurile pe care Ij dorii, n caz contrar, este posibil s deplasai prin reea valori BLOB posibil
foarte j fr absolut nici un rost. Aceasta este o alt situaie cnd informaia de identificare valorilor BLOB,
stocat ntr-o alt coloan, poate fi util. Putei cuta n coloana respec-l tiv pentru a determina rndul sau
rndurile pe care le dorii, dup care regsii valqa4| rea BLOB din rndurile corespunztoare.
Deplasai valorile BLOB ntr-un tabel separat, n anumite situaii, este justificat mutarea coloanelor BLOB
dintr-un tabel n alt tabel secundar, dac acest lucru v pe mite s convertii tabelul ntr-un format cu rnduri de
lungime fix pentru coloane rmase. Acest procedeu va reduce fragmentarea n tabelul primar si, de asemenea,
permite s profitai de plusul de performan determinat de rndurile cu lungime fixll
3 Valoare numeric rezultat printr-o transformare cunoscut sub numele de funcie hash (n cazul nos-|| tru
MD5) care convertete un identificator sau o cheie, care au o anumit semnificaie pentru utiliza-ii, tor, ntr-o
valoare care indic locul ocupat de date ntr-un tabel. (Cf. Dicionar de calculatoare,^ Editura Teora, 1999.) N.T.
'
'S
Capitolul 4 Optimizarea interogrilor
209
ncrcarea eficient a datelor
Probabil c n majoritatea timpului vei fi preocupat de optimizarea interogrilor SELECT, deoarece acestea sunt
cele mai folosite tipuri de interogri si deoarece modul de optimizare a acestora nu este ntotdeauna simplu de
intuit. Prin comparaie, ncrcarea datelor n baza dumneavoastr de date este o operaie simpl. Totui, exist
strategii pe care le putei folosi pentru a mbunti eficiena operaiunilor de ncrcare a datelor. Principiile de
baz sunt urmtoarele:
ncrcarea unor mari cantiti de date este mai rapid dect ncrcarea unui singur rnd, deoarece zona cache a
indexului nu trebuie golit dup ncrcarea fiecrei nregistrri; golirea poate avea loc la ncheierea lotului de
nregistrri.
ncrcarea este mai rapid atunci c$nd un tabel nu are indexuri dect atunci cnd este indexat. Dac exist
indexuri, este necesar nu numai adugarea nregistrrii la fiierul de date, dar fiecare index trebuie modificat
pentru a reflecta adugarea noii nregistrri.
Instruciunile SQL mai scurte sunt mai rapide dect instruciunile mai lungi, deoarece implic o analiz mai
redus din partea serverului i deoarece pot fi trimise mai rapid prin reea de la client la server.
Unii din aceti factori pot prea minori (mai ales ultimul), dar, dac ncrcai o mulime de date, chiar si micile
trucuri de sporire a eficienei determin o diferen. Putem folosi principiile generale anterioare pentru a trage
numeroase concluzii practice cu privire la modul cel mai rapid de ncrcare a datelor:
Instruciunea LOAD DATA, n toate formele sale, este mai eficient dect INSERT, deoarece ncarc rndurile
n cantiti mari. Golirea zonei cache a indexului are loc mai puin frecvent i serverul trebuie s analizeze i s
interpreteze o singur instruciune, n loc de mai multe.
LOAD DATA este mai eficient dect LOAD DATA LOCAL. Dac se folosete instruciunea LOAD DATA,
fiierul trebuie s se afle n server i dumneavoastr trebuie s avei privilegiul FILE, dar serverul poate citi
fiierul direct de pe disc. Cu instruciunea LOAD DATA LOCAL, clientul citete fiierul si l trimite n reea
serverului, ceea ce reprezint o operaie mai lent.
Dac trebuie s folosii INSERT, utilizai forma care permite specificarea mai multor rnduri n aceeai
instruciune:
INSERT INTO nume_tabel VALUES( ...),(...),...
Cu ct se pot specifica numere de rnduri mai mari n cadrul instruciunii, cu att mai bine. Astfel se reduce
numrul total de instruciuni de care avei nevoie i se reduce numrul de goliri ale zonei cache a indexului.
Dac folosii mysqldump pentru a genera fiiere copii de siguran pentru baza de date, folosii opiunea
--extended -insert, astfel nct fiierul de descrcare s conin instruciuni INSERT pentru mai multe rnduri. De
asemenea, putei folosi - -opt (optimizare), care activeaz opiunea - -extended -insert. Pe de alt parte, evitai
utilizarea opiunii - -complete -insert cu mysqldump; instruciunile INSERT rezultante vor fi pentru rnduri
individuale, vor fi mai lungi i vor necesita un volum suplimentar de analiz dect instruciunile generate fr -complete-insert.
B- >'.m
i.Y^i
210
Partea l Utilizarea general a sistemului MySQL
Folosii protocolul client/server comprimat pentru a reduce cantitatea de date trec prin reea. Pentru majoritatea

clienilor MySQL, acest lucru se poate specific folosind opiunea pentru linia de comand --compress, n general,
acest protocol i va folosi numai pe reelele lente, deoarece comprimarea folosete o mare parte timpul
procesorului.
Lsai sistemul MySQL s insereze automat valorile prestabilite; nu specificai, instruciunile INSERT,
coloanele crora le va fi oricum atribuit valoarea prestabilii! n medie, instruciunile dumneavoastr vor fi mai
scurte, ceea ce va reduce numr! de caractere trimise prin reea ctre server, n plus, deoarece instruciunile
conin i puine valori, serverul execut un volum de analiz mai redus i conversii de valori i puine.
Dac un tabel este indexat, putei diminua suprasarcina determinat de indexare pti utilizarea inseriilor
grupate pe loturi (instruciunea LOAD DATA sau instruciuni INSE pentru mai multe rnduri). Acestea reduc la
minimum impactul actualizrii indexuli) deoarece zona cache a indexului trebuie golit numai dup ce toate
rndurile au'. prelucrate, nu dup fiecare rnd n parte.
Dac trebuie s ncrcai foarte multe date ntr-un tabel nou pentru a-1 popula, mai rapid s creai tabelul fr
indexuri, s ncrcai datele i apoi s creai indexur Este mai rapid s creai toate indexurile simultan, n loc de a
le modifica pentru fie rnd n parte.
ncrcarea datelor ntr-un tabel indexat poate fi mai rapid dac tergei sau dez vai indexurile nainte de
ncrcare i le reconstruii sau le reactivai ulterior.
Dac dorii s folosii strategia de tergere sau dezactivare a indexurilor pentru carea datelor, pregtii-v s
facei unele experimente, pentru a vedea dac merit, i ncrcai o cantitate mic de date ntr-un tabel mare,
construirea indexurilor poatel mai mult timp dect ncrcarea datelor.)
Putei terge si reconstrui indexuri cu DROP INDEX si CREATE INDEX. O metod alt tiv este de a dezactiva
si reactiva indexurile folosind myisamchk sau isamchk. metod v impune s avei un cont n calculatorul gazd
al serverului MySQL i s i acces de scriere n fiierele tabelului. Pentru a dezactiva indexurile unui tabel,
catalogul adecvat al bazei de date i rulai una din urmtoarele comenzi:
% myisamchk --keys-used=0 nume_tabel
% isamchk --keys-used=0 nume_tabel Folosii myisamchk pentru tabelele MylSAM, care au un fiier index cu
extensia .1 respectiv isamchk pentru tabelele ISAM, care au un fiier index cu extensia . ISM. ncrcarea
tabelului cu date, reactivai indexurile:
% myisamchk --recover --quick --keys-used=n nume_tabel
% isamchk --recover --quick --keys-used=n nume_tabel n este numrul de indexuri pe care l are tabelul. Putei
determina aceast valoare' invocarea utilitarului adecvat cu opiunea -description:
vff|
% myisamchk --description nume_tabel
% isamchk --description nume_tabel
Capitolul 4 Optimizarea interogrilor
211
Dac decidei s folosii dezactivarea i activarea indexurilor, trebuie s folosii protocolul de blocare pentru
repararea tabelului, descris n capitolul 13, ntreinerea i repararea bazelor de date", pentru a mpiedica serverul
s modifice tabelul n acelai timp cu dumneavoastr. (De fapt nu reparai tabelul, dar l modificai ntr-o
manier similar cu procedura de reparare a tabelelor, deci este adecvat folosirea aceluiai protocol.)
Principiile prezentate anterior de ncrcare a datelor se aplic i n mediile cu interogri mixte, care implic
clieni ce execut diferite categorii de operaii. De exemplu, n general dorii s evitai interogri SELECT care
dureaz mult pe tabele care sunt actualizate frecvent. Astfel, rezult o competiie acerb ntre clienii care scriu
date si o performan redus a acestora. O modalitate posibil de a evita aceast situaie, dac scrierile dumneavoastr sunt n majoritate operaii INSERT, este de a aduga noi nregistrri ntr-un tabel temporar i apoi de
a aduga periodic acele nregistrri n tabelul principal. Aceasta nu este o strategie viabil dac dorii s obinei
acces imediat la noile nregistrri, dar, dac v putei permite s le lsai inaccesibile pentru o scurt perioad de
timp, utilizarea tabelului temporar v va fi de folos din dou puncte de vedere. Primul: reduce competiia ntre
interogrile SELECT care au loc asupra tabelului principal, deci acestea se execut mai rapid. AI doilea: este
necesar un timp total mai redus pentru ncrcarea unui lot de nregistrri din tabelul temporar n tabelul principal
dect cel necesar pentru ncrcarea individual a nregistrrilor; zona cache a indexului trebuie s fie golit
numai la finalul fiecrui lot, nu dup fiecare rnd n parte.
O aplicaie a acestei strategii este atunci cnd consemnai n jurnal numrul de deschideri al paginii Web din
serverul dumneavoastr Web ntr-o baz de date MySQL. n acest caz, probabil c nu este foarte important s v
asigurai c intrrile ajung imediat n tabelul principal.
O alt strategie pentru a reduce numrul de goliri ale zonei cache a indexului este de a folosi opiunea de creare a
tabelului DELAYED_KEY_WRITE pentru tabelele MylSAM, dac datele dumneavoastr sunt de aa natur
nct nu este absolut esenial ca fiecare nregistrare s fie inserat n cazul unei nchideri anormale a sistemului.
(Aceast situaie poate aprea dac folosii MySQL pentru consemnri n jurnale.) Opiunea determin golirea
ocazional a zonei cache a indexului, nu dup fiecare inserie.
Dac dorii s folosii golirea ntrziat a zonei cache a indexului la nivel de server, lansai utilitarul mysqld cu
opiunea --delayed-key-write. n acest caz, scrierile n blocul index sunt ntrziate pn cnd blocurile trebuie
evacuate pentru a face loc altor valori ale indexului, pn la execuia unei comenzi f lush-tables sau pn la

nchiderea tabelului indexat.


Probleme de planificare si de blocare
Seciunile anterioare s-au concentrat mai ales asupra creterii vitezei interogrilor individuale. MySQL v mai
permite s modificai prioritile de planificare a execuiei instruciunilor, ceea ce poate duce la o mai bun
colaborare ntre interogrile care provin de U diferii clieni, astfel nct clienii individuali s nu rmn blocai
pentru o perioad Prea lung de timp. De asemenea, modificarea prioritilor poate garanta faptul c anumite
categorii de interogri sunt prelucrate mai rapid. Vom examina mai nti politica de
212
Partea l Utilizarea general a sistemului MySQL
planificare prestabilit a sistemului MySQL i apoi vom vedea care sunt opiunile, care le avei la dispoziie
pentru influenarea acestei politici. Pentru aceast expunere,! client care execut o regsire (o instruciune
SELECT) este un client de citire. Un clij care execut o operaie care modific un tabel (instruciunile DELETE,
INSERT, REPL sau UPDATE) este un client de scriere.
n esen, politica de planificare din MySQL poate fi rezumat astfel:
Cererile de scriere trebuie s fie prelucrate n ordinea n care sosesc.
Scrierile au o prioritate mai mare dect citirile.
Politica de planificare este implementat cu ajutorul blocrilor de tabel. De fiecare dl cnd un client obine
accesul la un tabel, mai nti este necesar procurarea unei blo| pentru tabelul respectiv. Se poate face acest lucru
n mod explicit, cu ajutorul instruct nii LOCK TABLES, dar n mod normal utilitarul de gestionare a blocrilor
din ser procur automat blocrile, conform necesitailor. Cnd clientul a terminat lucrul cu J tabel, blocarea
tabelului poate fi eliminat. O blocare obinut n mod explicit este elii nat cu instruciunea UNLOCK
TABLES, dar i n acest caz serverul elibereaz autoi blocrile pe care le-a obinut.
*.
Un client care efectueaz o operaie de scriere trebuie s dispun de o blocare pe acces exclusiv la tabel. Tabelul
este ntr-o stare nedefinit n timpul desfurrii operaf deoarece nregistrrile de date sunt terse, adugate sau
modificate, iar toate inde din tabel trebuie actualizate pentru a reflecta modificrile. A permite altor clieni s;
acces la tabel n timp ce acesta se afl n flux nseamn a provoca probleme. Este goric contraindicat a se permite
la doi clieni s scrie n tabel n acelai timp, deoar astfel tabelul s-ar deteriora rapid, transformndu-se ntr-o
dezordine inutilizabil. | este recomandat nici citirea de ctre un client a unui tabel aflat n flux, deoarece:
posibil ca tabelul s se modifice exact n regiunea n care este citit, ceea ce nseamn| rezultatele ar fi incorecte.
Un client care efectueaz o operaie de citire trebuie s dispun de o blocare, pentt mpiedica pe ali clieni s
scrie n tabel, astfel nct tabelul s nu se modifice n este citit. Totui, blocarea nu trebuie s furnizeze acces
exclusiv pentru citire. Blc poate permite citirea tabelului de ctre ali clieni n acelai timp. Prin citire tabeliy se
modific, deci nu exist nici un motiv pentru care clienii de citire trebuie mpiedice reciproc s obin acces la
tabel.
MySQL v permite sa influenai politica sa de planificare prin intermediul a nur modificatori de interogare.
Unul din acetia este cuvntul cheie LOW_PRIORITY (pripi redus) pentru instruciunile DELETE, INSERT,
LOAD DATA, REPLACE i UPDATE. Un altul cuvntul cheie HIGH_PRIORITY (prioritate ridicat) pentru
instruciunile SELECT, de-al treilea este cuvntul cheie DELAYED (amnat) pentru instruciunile INS
REPLACE.
Cuvntul cheie LOW_PRIORITY influeneaz planificarea operaiilor dup cum urme mod normal, dac o
operaie de scriere ntr-un tabel ajunge n timp ce tabelul est clientul de scriere se blocheaz pn cnd clientul
de citire i termin execuia d? o interogare, o dat pornit, nu poate fi ntrerupt. Dac sosete o alt cerere de
timp ce clientul de scriere ateapt, se va bloca i clientul de citire deoarece, con:
Capitolul 4 Optimizarea interogrilor
213
politicii de planificare prestabilite, clienii de scriere au prioritate mai mare dect clienii de citire. Cnd primul
client de citire i-a terminat execuia, clientul de scriere i ncepe execuia, iar cnd acesta din urm termin, al
doilea client de citire i ncepe execuia.
n cazul n care cererea de scriere este o cerere cu prioritate redus, se consider c scrierea nu are o prioritate
mai ridicat dect citirile. In acest caz, dac o a doua cerere de citire sosete n timp ce clientul de scriere
ateapt, al doilea client de citire este autorizat s treac naintea clientului de scriere. Clientul de scriere are
permisiunea de a continua numai atunci cnd nu mai exist clieni de citire. O implicaie a acestei modificri n
planificarea operaiilor este aceea c, teoretic, este posibil ca scrierile cu prioritate redus s fie blocate la infinit.
Dac sosesc noi cereri de citire cnd cererile anterioare sunt nc n curs de desfurare, noile cereri vor avea
permisiunea de a fi executate anterior scrierii cu prioritate redus.
Cuvntul cheie HIGH_PRIORITY pentru interogrile SELECT este similar; permite unei instruciuni SELECT
s fie executat anterior unei scrieri aflate n ateptare, chiar dac scrierea are prioritate normal.
Modificatorul DELAYED pentru instruciunea INSERT se comport astfel: atunci carid pentru un tabel sosete o
cerere INSERT DELAYED, serverul aaz rndurile ntr-o coad i returneaz imediat clientului o stare, astfel
nct clientul s-i poat ncepe execuia chiar nainte de inseria rndurilor, n cazul n care clienii citesc din
tabel, rndurile din coad sunt pstrate. Cnd nu mai exist clieni de citire, serverul ncepe s insereze rndurile

din coada cu rnduri amnate. Ocazional, serverul face o pauz, pentru a vedea dac au sosit cereri de citire noi
i dac acestea se afl n ateptare, n acest caz, coada cu rnduri amnate este suspendat i clienilor de citire li
se permite s-i nceap execuia. Cnd nu au mai rmas clieni de citire, serverul rencepe s insereze rndurile
amnate. Acest proces continu pn cnd coada se golete.
Modificatorii de planificare nu au aprut n MySQL toi deodat. Tabelul urmtor prezint aceti modificatori i
versiunea programului MySQL n care au aprut. Putei folosi acest tabel pentru a determina caracteristicile
versiunii dumneavoastr de MySQL.
Tipul instruciunii
DELETE LOW_PRIORITY
INSERT LOW_PRIORITY
INSERT DELAYED
LOAD DATA LOW_PRIORITY
LOCK TABLES ... LOW_PRIORITY
REPLACE LOW_PRIORITY
REPLACE DELAYED
SELECT ... HIGH PRIORITY
UPDATE LOW PRIORITY
SET SQL LOW PRIORITY UPDATES
Versiunea primei apariii
3.22.5
3.22.5
3.22.15
3.23.0
3.22.8
3.22.5
3.22.15
3.22.9
3.22.5
3.22.5
214
Partea l Utilizarea general a sistemului MySQL
Efecte de margine pe parte de client ale instruciunii INSERT DELAYED
Instruciunea INSERT DELAYED este util dac ali clieni ruleaz instruciuni SELECT lungi i nu i s blocai
ali clieni n ateptarea finalizrii insertiei. Clientul care emte instruciunea INSERT DELAY se poate executa
mai rapid, deoarece serverul pur i simplu asaz la coad rndul care trebuie in
Totui, trebuie s cunoatei i alte diferene ntre instruciunile INSERT normale i comportarea ir unii INSERT
DELAYED. Clientul primete o eroare dac instruciunea INSERT conine o eroare de i tax, dar alte informaii
care erau disponibile n mod normal nu mai sunt acum accesibile. De exemplu,^ vei putea obine valoarea
AUTO_INCREMENT atunci cnd instruciunea retumeaz. De asemenea, j vei obine un numr de duplicate al
valorilor din indexurile unice. Aceasta se ntmpl deoarece open de inserie retumeaz o stare nainte de
finalizarea efectiv a operaiei. O alt implicaie este aceea'd dac rndurile din instruciunile INSERT
DELAYED sunt puse la coad n timp ce ateapt s fie i rate i serverul sufer o cdere sau este suprimat (cu
instruciunea kill -9), rndurile se vor | Acest fapt nu este valabil pentru o suprimare TERM normal; n situaia
respectiv, serverul va insera i durile nainte de a-i ncheia execuia.
Optimizare pentru administratori
Seciunile anterioare au descris optimizri care pot fi efectuate de ctre utiliza obinuii ai sistemului MySQL,
privind operaiile de creare i indexare a tabelelor, legate de interogri. Exist ns si optimizri care pot fi
efectuate numai de ctre adr tratorii MySQL si de sistem, care dein controlul asupra serverului MySQL sau
calculatorului pe care ruleaz acesta. Unii parametri ai serverului au o legtur dire prelucrarea interogrilor si
pot fi ajustai, dup cum anumite aspecte legate de configur componentelor hardware au un efect direct asupra
vitezei de prelucrare a interogrile
Parametrii serverului
Serverul are parametri (variabile) generali pe care i putei modifica pentru a-i infh modul de operare. O
expunere general referitoare la ajustarea parametrilor serve este dat n capitolul 11, Administrarea general a
sistemului MySQL", dar o parej aceti parametri sunt corelai mai ales cu prelucrarea interogrilor i merit o se
prezentare n acest cadru:
delayed_queue_size
Acest parametru determin numrul de rnduri din instruciunile INSERT DEi care vor fi stocate n coad
anterior blocrii clienilor care execut alte inst INSERT DELAYED. Mrirea acestei valori permite serverului s
accepte mai multe jj duri de la acest tip de cerere, astfel nct clienii s se poat executa fr blocare, j
key_buffer_size

Aceasta este dimensiunea bufferului folosit pentru stocarea blocurilor de index, j dispunei de memoria necesar,
mrirea acestei valori trebuie s mbunteasc i valul de timp necesar pentru crearea si modificarea indexului.
Valori mai ridicat acestui parametru permit sistemului MySQL s stocheze n memorie maij-;i blocuri de index
simultan, ceea ce mrete probabilitatea de gsire a valorilor chfiS memorie, fr a fi necesar citirea unui bloc
nou de pe disc.
^
Capitolul 4 Optimizarea interogrilor
215
n MySQL 3.23 i n versiunile ulterioare, dac mrii dimensiunea bufferului pentru stocarea cheilor, putei
porni serverul folosind opiunea --init-file. Aceasta permite specificarea unui fiier de instruciuni SQL, care s
fie executate la pornirea serverului. Dac avei tabele numai pentru citire pe care dorii s le stocai n memorie,
le putei copia n tabele HEAP, pentru a executa cutri foarte rapide n index.
Aspecte legate de componentele hardware
Pentru mbuntirea performanelor serverului, v putei folosi componentele hardware ntr-o manier mai
eficient:
Instalai o cantitate mai mare de memorie n calculatorul dumneavoastr. Aceasta v permite s mrii
dimensiunile zonei cache i a bufferelor din memoria serverului. De asemenea, permite serverului s foloseasc
mai frecvent informaiile stocate n memorie i s necesite mai puine operaii de preluare a informaiilor de pe
disc.
Reconfigurai sistemul astfel nct s elimine toate dispozitivele de schimb de memorie cu discul, dac avei o
cantitate de RAM suficient pentru a efectua toate operaiile de schimb ntr-un sistem de fiiere din memorie, n
caz contrar, unele sisteme vor continua s mprumute" memorie de pe disc, chiar dac avei o cantitate
suficient de memorie RAM pentru operaiile de schimb.
Adugai discuri mai rapide pentru a mbunti latena I/O. n mod caracteristic, timpul de cutare este
elementul hotrtor pentru performan n acest caz. Deplasarea capetelor de citire n lateral este o operaie lent;
odat capetele poziionate, citirea blocurilor din afara pistei este, comparativ, mai rapid.
ncercai s redistribuii activitatea discului pe dispozitive fizice. De exemplu, dac v putei stoca dou dintre
cele mai solicitate baze de date ale dumneavoastr pe uniti fizice separate, procedai n acest sens. Reinei c
utilizarea a diferite partiii pe acelai dispozitiv fizic nu este suficient. Acest lucru nu v va fi de folos, deoarece
partiiile vor continua s concureze pentru aceeai resurs fizic (n spe capetele discului). Procedura pentru
mutarea bazelor de date este descris n capitolul 10, Catalogul de date MySQL".
nainte de a muta datele ntr-un alt dispozitiv, asigurai-v c nelegei caracteristicile de ncrcare ale sistemului
dumneavoastr. Dac o alt activitate important este deja n curs de desfurare pe un anumit dispozitiv fizic,
inseria unei baze de date n acel dispozitiv nu ar face dect s nruteasc performanele. De exemplu, nu vei
obine nici un avantaj global dac prelucrai o mare cantitate de trafic Web i mutai o baz de date n
dispozitivul unde este localizat arborele document al serverului dumneavoastr Web. (Dac dispunei numai de o
singur unitate, nu avei cum s procedai la o redistribuire a activitii discului, desigur.)
Cnd construii MySQL, configurai-1 astfel nct s foloseasc biblioteci statice, nu biblioteci partajate.
Fiierele binare dinamice care folosesc bibliotecile partajate determin economii de spaiu pe disc, dar fiierele
binare statice sunt mai rapide. (Totui, nu putei folosi fiiere binare statice dac dorii s ncrcai funcii definite
de utilizator, deoarece mecanismul UDF se bazeaz pe legturi dinamice.)
B4^
*s >\aS*
PARTEA A-ll A
Utilizarea interfeelor de programare
ale sistemului MySQL
5 Introducere n programarea MySQL
6 Interfaa API MySQL pentru C
7 Interfaa API pentru Perl DBI
8 Interfaa API pentru PHP
CAPITOLUL 5
Introducere n programarea MySQL
n aceast parte a crii, vom discuta despre ceea ce trebuie s tii pentru a v scrie pr priile dumneavoastr
programe care obin accesul la bazele de date MySQL. MySC vine cu un set de programe utilitare. De exemplu,
mysqldump export coninutul definiiile structurii tabelelor, msqlimport ncarc fiierele de date n tabele,
mysqladmjj execut operaii administrative, iar mysql v permite s interacionai cu serverul pent a executa
interogri arbitrare. Fiecare din utilitarele standard din MySQL este conce ca un program mic, cu o anumit
finalitate i cu o funcie specific, limitat. Acest luc este adevrat chiar i pentru mysql, care este mai flexibil
dect celelalte utilitare, n se sul c l putei folosi pentru a executa orice numr de interogri diferite: este conce
cu scopul unic de a v permite s emitei instruciuni SQL direct ctre server i s1 lizai rezultatele.
Aceast natur limitat a clienilor MySQL nu este un neajuns, ci deriv din proiect Programele sunt utilitare de

uz general; nu sunt menite a anticipa toate posibilele cer pe care le putei avea. Dezvoltatorii sistemului MySQL
nu sunt adepi ai principiului | a scrie programe imense, de dimensiuni excesive, care ncearc s fac orice ai
putea d<| s facei (sfrind astfel prin a include mari cantiti de program pentru lucruri care i v intereseaz
ctui de puin). Cu toate acestea, uneori aplicaiile au cerine care nu j fi rezolvate prin funcionalitile
programelor client standard. Pentru a aborda cazuri, MySQL furnizeaz o bibliotec de programare a clienilor.
Aceasta v permit v scriei propriile dumneavoastr programe i v ofer flexibilitatea de a satisface cerinele
specializate pe care aplicaiile dumneavoastr le-ar putea avea. Oferindu acces la serverul MySQL, biblioteca
client deschide posibiliti limitate numai de pria dumneavoastr imaginaie.
Care sunt acele funcionaliti specifice pe care le putei acumula scriindu-v propl programe? S examinm
aceast ntrebare comparativ cu funcionalitile clier mysql i a interfeei sale simple cu serverul MySQL:
Putei personaliza metodele de manipulare a datelor de intrare. Cu mysql, ii ducei instruciuni SQL brute. Cu
propriile dumneavoastr programe, putei utilizatorului metode de introducere a datelor mai intuitive i mai uor
de foi Programul poate elimina necesitatea ca utilizatorul s cunoasc limbajul SQL i i pe aceea de a cunoate
rolul bazei de date n operaia care se execut.
Colecia de date de intrare poate fi ceva rudimentar, ca un ciclu de citire a promf i a valorilor introduse ntr-o
interfa n stil linie de comand, respectiv ceva : cat, ca un formular de introducere a datelor bazat pe ecran,
implementat folosir
Capitolul 5 Introducere n programarea MySQL
219
pachet de gestiune a ecranului precum curses sau S-Lang, un sistem X (window) care folosete Tcl/Tk sau un
formular dintr-un browser Web.
Pentru majoritatea utilizatorilor, specificarea parametrilor de cutare este cu mult mai simpl prin completarea
unui formular dect prin emiterea unei instruciuni SELECT. De exemplu, un agent imobiliar care caut case
care se ncadreaz ntr-un anumit domeniu de pre, construite ntr-un anumit stil sau amplasate ntr-o anumit
locaie nu dorete dect s introduc parametrii de cutare ntr-un formular si s primeasc ofertele
corespunztoare cu un minimum de deranj. Pentru introducerea de noi nregistrri sau actualizarea nregistrrilor
existente, sunt valabile consideraii similare. O dactilograf dintr-un departament de introducere a datelor nu
trebuie s cunoasc sintaxa SQL pentru instruciunile INSERT, REPLACE sau UPDATE.
Un motiv suplimentar pentru interpunerea unui nivel de colectare a datelor de intrare ntre utilizatorul final si
serverul MySQL este acela c putei valida datele de intrare introduse de utilizator. De exemplu, putei verifica
datele, pentru a v asigura c acestea corespund formatului ateptat de MySQL, sau putei impune completarea
anumitor cmpuri.
> Putei personaliza datele de ieire, n esen, datele de ieire ale programului mysql sunt neformatate; putei
alege un stil tabular (sau delimitat prin tabulatori). Dac dorii date de ieire ntr-un format mai estetic, trebuie s
le formatai dumneavoastr personal. Aceast formatare variaz ntre operaii simple (cum ar fi a scrie
Inexistent" n loc de NULL) si pn la cerine mai complexe de generare a rapoartelor. S lum n considerare
urmtorul raport:
Stat Ora
Vnzri
AZ Mesa Phoenix
94384,24 USD
17328,28 USD
subtotal

117712,52 USD

CA Los Angeles
Oakland

118198,18 USD
38838,36 USD

Subtotal

157036,54 USD

TOTAL GENERAL 274749,06 USD


Acest raport include numeroase elemente specializate:
Antete personalizate.
Eliminarea valorilor care se repet n coloana Stat, astfel nct valorile s fie afiate numai atunci cnd se
modific.
Calcule de subtotal i total general.
Formatarea numerelor, cum este 94384,24, ca valori exprimate n dolari, adic 94384,24 USD.
Pentru unele categorii de sarcini, nici mcar nu avei nevoie de date de ieire. Poate c pur i simplu regsii
informaii pentru a calcula un rezultat pe care l inserai ntr-un alt tabel din baza de date. Poate chiar dorii ca
datele de ieire s ajung n alt parte
220
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
dect la utilizatorul care ruleaz interogarea. De exemplu, dac extragei nume i adres de e-mail pentru a
alimenta n mod automat un proces care genereaz scrisori tip pen| tru mesaje de e-mail n cantiti mari,
programul dumneavoastr produce date de ieir Dar datele de ieire sunt alctuite din mesaje care se deplaseaz

la destinatarii mesaje de e-mail, nu la persoana care ruleaz programul.


Putei evita restriciile impuse de natura intrinsec a limbajului SQL. SQL nu i
un limbaj procedural, cu un set de structuri de control al fluxului, cum st condiionalele, ciclurile sau subrutinele.
Scripturile SQL sunt compuse dintr-un set < instruciuni care se execut una cte una, de la nceput la sfrit, cu
o minim ver care a apariiei erorilor.
Dac executai un fiier cu interogri SQL folosind mysql n modul batch, mysql fie 115 renuna dup prima
eroare, fie - dac specificai opiunea --force - execut tots interogrile fr nici o discriminare, indiferent de
numrul de erori care se produc. program poate asigura controlul fluxului n jurul instruciunilor, astfel nct
duopj neavoastr s v putei adapta n mod selectiv la starea de succes sau de ee interogrilor. Putei face
execuia unei interogri independent de reuita sau ee alteia sau putei lua decizii cu privire la urmtoarea
aciune n funcie de rezulta unei interogri anterioare.
SQL are o persisten foarte redus de-a lungul instruciunilor, fapt care se manife i la mysql. Este dificil
utilizarea rezultatelor unei interogri i aplicarea lor ntr-o j interogare, respectiv coroborarea rezultatelor mai
multor interogri. Func LAST_INSERT_ID() se poate folosi pentru a obine valoarea AUTO_INCREMENT cel
recent generat de o instruciune anterioar, dar cam asta e tot...
Mai general, se poate dovedi dificil regsirea unui set de nregistrri, urmat de Uzarea fiecreia ca baz pentru
o serie complex de alte operaii. De exemplu, regsii unei liste de clieni si apoi cutarea ntr-un istoric detaliat
al creditului pentru fiecj pot implica mai multe interogri pentru fiecare client, n anumite situaii, doritLii
producei o factur pentru care trebuie s asociai antetul facturii cu informaii despre client si despre fiecare
articol comandat, mysql nu este adecvat pentru ace categorii de operaii, att deoarece avei nevoie de mai multe
interogri care depind rezultatele unor interogri anterioare, precum si fiindc aceste operaii depesc pe
bilitile de formatare ale programului mysql.
n general, pentru operaii care implic relaii master-detaliu i care prezint ce complexe de formatare a datelor
de ieire este nevoie de un alt instrument dect my Un program asigur liantul care coreleaz interogrile i care
v permite s fok datele de ieire ale unei interogri ca date de intrare pentru alta.
Putei integra MySQL n orice aplicaie. Multe programe i extrag avantajele capacitatea de a exploata
capacitatea unui sistem de baze de date de a furniza infu maii. O aplicaie care trebuie s verifice un numr de
client sau s afle dac un ; mit articol se gsete sau nu n inventar poate efectua aceast operaie prin emit unei
interogri rapide. O aplicaie Web care permite unui client s solicite toate i scrise de un anumit autor le poate
cuta pe acestea ntr-o baz de date i apoi pre ta rezultatele browserului clientului.
Capitolul 5 Introducere n programarea MySQL
221
Este posibil realizarea unui grad rudimentar de integrare" prin utilizarea unui script de interpreter care invoc
mysql cu un fiier de intrare care conine instruciuni SQL, iar apoi prin postprocesarea datelor de ieire folosind
alte utilitare UNIX. Acest procedeu poate deveni neatractiv, pe msur ce operaia dumneavoastr progreseaz.
De asemenea, poate da o senzaie de genul merge, dar ceva nu-i n regul" pe msur ce aplicaia evolueaz
ntr-o crpeal dezordonat. De asemenea, suprasarcina de creare de proces a unui script de interpretor care
ruleaz alte comenzi poate fi mai mare dect dorii dumneavoastr s o creai. Poate fi mai eficient s
interacionai direct cu serverul MySQL, extrgnd exact informaiile de care avei nevoie pe msura necesitilor, n fiecare faz de execuie a aplicaiei dumneavoastr.
n ceea ce privete baza noastr de date demonstrativ samp_db pe care am configurat-o n capitolul l,
Introducere n MySQL si SQL", am enumerat acolo numeroase deziderate care ne impun s scriem programe
care s interacioneze cu serverul MySQL. Unele din aceste deziderate sunt prezentate n urmtoarea list:
Formatarea catalogului membrilor Ligii istorice n vederea tipririi
Facilitarea prezentrii catalogului si a cutrii n acesta din Internet
Trimiterea prin e-mail a ntiinrilor de plat a cotizaiei
Introducerea cu uurin a punctajelor n catalogul colar folosind un browser Web
Un domeniu pe care l vom trata n detaliu l constituie integrarea funcionalitilor sistemului MySQL ntr-un
mediu Web. MySQL nu furnizeaz suport direct pentru aplicaii Web dar, prin combinarea acestuia cu
instrumentele adecvate, bazele dumneavoastr de date vor deveni uor accesibile prin Web. Putei specifica
interogri folosind serverul dumneavoastr de Web i putei raporta rezultatele browserului unui client.
Exist dou perspective complementare ale csniciei" ntre MySQL i Web:
Interesul dumneavoastr primordial este baza de date, iar dumneavoastr dorii s folosii Web-ul ca instrument
pentru obinerea unui acces mai uor la date. Locul unui sistem de baze de date ntr-un atare scenariu este
explicit i evident, deoarece este punctul focal al interesului dumneavoastr. De exemplu, putei scrie pagini Web
care v permit s vedei care sunt tabelele pe care le conine baza dumneavoastr de date, care este structura
fiecrui tabel i care este coninutul acestuia. Serverul Web l folosii pentru a mbunti accesul la MySQL.
Acesta este punctul de vedere probabil al unui administrator MySQL.
Interesul dumneavoastr fundamental poate fi situl Web, i putei dori s folosii MySQL ca instrument pentru a
spori valoarea coninutului sitului dumneavoastr pentru persoanele care l viziteaz. De exemplu, dac rulai un
avizier electronic sau o list de discuii pentru vizitatorii sitului, putei folosi MySQL pentru a ine evidena

mesajelor, n acest caz, rolul sistemului de baze de date este mai subtil si este posibil chiar ca vizitatorii s nu-si
dea seama c acesta este angrenat n serviciile pe care le oferii. Folosii MySQL pentru a extinde
funcionalitile serverului dumneavoastr de Web. Acesta este, probabil, punctul de vedere al dezvoltatorului
unui sit Web.
Aceste perspective nu sunt mutual exclusive. De exemplu, n scenariul care implic Liga istoric, dorim s
folosim Web-ul ca mijloc pentru ca membrii s obin un acces rapid la coninutul catalogului cu membri,
punnd rubricile catalogului la dispoziie prin Internet.
222
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Aceasta constituie o utilizare a Web-ului pentru furnizarea accesului la baza de date.! acelai timp, situl Web al
Ligii este oarecum subdezvoltat", deci inseria n cadrul sitult a coninutului catalogului mrete valoarea sitului
n ochii membrilor. Aceasta este o utif lizare a sistemului de baze de date pentru extinderea serviciilor furnizate
de sit.
Indiferent de modul n care vedei integrarea sistemului MySQL cu Web-ul, impleme tarea este similar.
Conectai interfaa icului dumneavoastr Web la componenta end MySQL, folosind serverul Web ca
intermediar. Serverul Web trimite o interogare < la utilizator ctre serverul MySQL, regsete rezultatele
interogrii si apoi le transmit clientului n vederea vizualizrii ntr-un browser.
Nu dorii s v punei datele n reea, desigur, dar uneori aceast operaie i are avantaje sale, mai ales n
comparaie cu accesul la datele dumneavoastr prin intermediul pr gramelor client MySQL standard:
Persoanele care obin accesul la datele dumneavoastr prin intermediul Web-ului folosi browserul pe care l
prefer, pe tipul de platform pe care l prefer. Nimeni nu < obligat s foloseasc numai sistemele pe care pot
rula programele client MySQL.". diferent de aria de acoperire a clienilor MySQL, browserele Web sunt si mai
rsp
Utilizarea unei interfee Web poate deveni mai simpl dect un client autonc MySQL n linie de comand.
O interfa Web poate fi personalizat conform cerinelor unei anumite aplic Clienii MySQL sunt instrumente
de uz general, cu interfa fix.
Paginile Web dinamice extind posibilitile sistemului MySQL de a efectua oper care sunt dificil sau imposibil
de realizat folosind clienii MySQL. De exemplu l putei asambla o aplicaie care ncorporeaz un crucior de
cumprturi" electrc folosind numai clieni MySQL.
Pentru scrierea aplicaiilor bazate pe Web se poate folosi orice limbaj de programare, *< unele sunt mai adecvate
dect altele. Vom vedea acest lucru n seciunea Alegerea i interfee de programare a aplicaiilor".
Interfee de programare a aplicaiilor (API) disponibile pentru MySQL
Pentru facilitarea dezvoltrii aplicaiilor, MySQL furnizeaz o bibliotec client, scrisj limbajul de programare C,
care v permite s obinei accesul la bazele de date M) din interiorul oricrui program scris n C. Biblioteca
client implementeaz o interfa programare a aplicaiilor (API) care definete modul n care programele client
stabj i deruleaz comunicaiile cu serverul.
Totui, nu suntei obligat s folosii numai limbajul C pentru a scrie programe M> Multe alte procesoare de
limbaj sunt fie scrise n C, fie au capacitatea de a folosi teci C, deci biblioteca client MySQL furnizeaz
mijloacele prin care asocierile My pentru aceste limbaje pot fi construite pe baza interfeei API pentru C. Aceast
fa v ofer numeroase opiuni pentru scrierea aplicaiilor care discut" cu se MySQL. Interfee API client exist
pentru Perl, PHP, Java, Python, C++, Tel i,;
Capitolul 5 Introducere n programarea MySQL
223
Cutai n manualul de referin MySQL sau n situl Web MySQL o list actualizat, deoarece ocazional sunt
adugate noi interfee API de limbaj.
Fiecare asociere de limbaj i definete propria sa interfa, care specific regulile de acces la MySQL. Spaiul nu
ne permite s discutm despre fiecare din interfeele API disponibile pentru MySQL, deci ne vom concentra
asupra a trei dintre cele mai populare:
Interfaa API a bibliotecii client n C. Aceasta este principala interfa de programare cu MySQL.
Interfaa API DBI (Database Interface) pentru limbajul de scripting de uz general Perl. DBI este implementat
ca un modul Perl, care interfaeaz cu alte module la nivelul DBD (Database Driver), fiecare modul furniznd
acces la un anumit tip de motor pentru baze de date. (Modulul DBD particular asupra cruia ne vom concentra
este cel care furnizeaz suport pentru MySQL, desigur.) Cele mai comune utilizri ale DBI pentru MySQL sunt
scrierea de clieni autonomi care sunt invocai de la linia de comand, precum i de scripturi destinate a fi
invocate de un server Web pentru a furniza acces din Web la MySQL.
Interfaa API pentru PHP. PHP este un limbaj de scripting care furnizeaz o modalitate convenabil de
nglobare a programelor n paginile Web. O asemenea pagin este prelucrat de PHP nainte de a fi trimis
clientului, ceea ce permite scriptului s genereze un coninut dinamic, cum ar fi includerea n pagin a
rezultatului unei interogri MySQL. Iniial, PHP avea semnificaia "Personal Home Page" (pagin de baz
personal), dar acest limbaj s-a dezvoltat mult dincolo de umilele sale nceputuri. Situl Web PHP folosete acum
numele n contextul "PHP: Hypertext Preprocessor", care face referire la sine nsui n aceeai manier ca i
GNU ("GNU's Not UNIX") (GNU nu este UNIX).

Construii pornind de la rezultatele muncii altora


Cnd clienii MySQL standard sunt insuficieni pentru necesitile dumneavoastr, nu este necesar ntotdeauna s
v scriei propriile programe. Alii s-au ocupat deja cu scrierea unor programe, din care multe sunt disponibile
gratuit. Vezi Anexa l, Instrumente utile produse de tere pri", pentru unele exemple. Este posibil s gsii
cteva care s v scuteasc de ceva munc.
Fiecare din aceste trei interfee API este prezentat n detaliu n propriul su capitol. Capitolul de fa conine o
trecere n revist comparativ a interfeelor API, pentru a descrie caracteristicile generale ale acestora i pentru a
v oferi o idee privind alegerea uneia n dauna alteia pentru o anumit aplicaie.
Desigur, nu avei nici un motiv s v considerai nepenit" ntr-o singur interfa API. nvai s cunoatei
fiecare interfa si narmai-v cu acele cunotine care v permit s facei o alegere neleapt. Dac avei un
proiect de mari dimensiuni, cu numeroase componente, putei folosi mai multe interfee API i putei scrie unele
componente ntr-un limbaj si alte componente ntr-un alt limbaj, n funcie de alegerea cea mai adecvat pentru
hecare parte a proiectului. De asemenea, este instructiv s implementai o aplicaie n mai multe moduri, dac
timpul v permite. Astfel, cptai o experien direct n utilizarea diferitelor interfee API, pe msur ce acestea
se aplic propriilor dumneavoastr aplicaii.
224
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Dac trebuie s v procurai programele necesare pentru utilizarea oricreia dintre intei feele API pe care dorii
s le ncercai, consultai Anexa A, Obinerea si instalarea pi gramelor", pentru a primi instruciuni.
3
Interfaa API pentru C
Interfaa API pentru C este folosit n contextul programelor C compilate. Aceasta e o bibliotec client care
furnizeaz interfaa de nivelul cel mai redus disponibil pehl comunicarea cu serverul MySQL, oferindu-v
funcionalitile de care avei nevoie pe stabilirea unei conexiuni cu serverul si conversaia cu acesta.
Predecesorii DBI si PHP
Predecesorul Peri al DBI este modulul Mysqlperl, i anume Mysql. pm. Acest modul nu mai este ac tat i nu
trebuie folosit pentru dezvoltarea noilor programe MySQL Un motiv este acela c Mysqlperl < dependent de
MySQL, n timp ce DBI nu este. Dac scriei aplicaii Peri pentru MySQL i apoi v i c dorii s le folosii cu
un alt motor pentru baze de date, portarea scripturilor DBI este mai simpl < aceea a scripturilor Mysqlperl,
deoarece primele sunt mai puin dependente de un anumit motor dej de date.
Dac v procurai un script Perl pentru accesul la MySQL i descoperii c, n loc de a fi scris pentru j este scris
pentru Mysqlperl, putei totui s folosii DBI. DBI poate fi construit astfel nct s includ s de emulare pentru
Mysqlperl, deci nu este necesar s instalai ambele pachete.
Predecesorul lui PHP 3 este PHP/FI 2.0 (FI este abrevierea de la form interpreter - interpreter de 1 lare). Ca i
Mysqlperl, PHP/FI este depit i nu vom mai discuta despre el.
v
Originea interfeei API n C cu MySQL
Dac avei experien n scrierea de programe pentru sistemul de gestiune a bazelor de date reia mSQL, vei
observa c interfaa API n C pentru MySQL este similar cu interfaa API n C cores toare pentru mSQL. Cnd
dezvoltatorii MySQL au nceput s-i implementeze motorul SQL propriii^ tru mSQL erau disponibile un numr
de utilitare gratuite. Pentru a face posibil portarea acelor i mSQL ctre MySQL cu minimum de dificultate,
interfaa API MySQL a fost proiectat intenionat ( nct s fie similar cu interfaa API pentru mSQL. (MySQL
este chiar dotat cu un script msq!2n care execut substituii textuale simple al numelor de funcii din interfaa
AP) pentru mSQL n MySQL corespunztoare. Aceast operaie este relativ simpl, dar execut o bun parte din
ac impus de conversia unui program mSQL n vederea utilizrii cu MySQL.)
Clienii C furnizai n distribuia MySQL sunt bazai pe aceast interfa API. JJi teca client C mai servete i
drept baz pentru asocierile MySQL cu alte limbai excepia interfeelor API pentru Java. De exemplu, driverul
specific MySQL modulul Perl DBI si programul PHP au devenit ambele compatibile cu MySQM legarea
codului pentru biblioteca client n C pentru MySQL. (Acest proces este ilu| n instruciunile de instalare a
modulelor DBI i PHP din Anexa A.)
Interfaa API pentru modulul Perl DBI
Interfaa API pentru DBI este folosit n contextul aplicaiilor scrise pentru limb scripting Perl. Aceasta este
interfaa care conine arhitectura pe cele mai multe etaje$j cele trei interfee API despre care vom discuta,
deoarece ncearc s lucreze cu uri'i
Capitolul 5 Introducere n programarea MySQL
225
de sisteme de baze de date ct mai mare posibil, ascunznd n acelai timp generatorului de scripturi ct mai
multe detalii specifice.
DBI este implementat prin intermediul modulelor Perl care folosesc o arhitectur cu dou niveluri (vezi figura
5.1):
Nivelul DBI (interfa cu baza de date). Furnizeaz interfaa pentru scripturi client. Acest nivel furnizeaz o
abstractizare care nu face referire la motoare pentru baze de date specifice.
Nivelul DBD (driver pentru baze de date). La acest nivel este furnizat un suport pentru diferite motoare de baze

de date, de ctre drivere care sunt specifice fiecrui motor de baze de date.
Nivel de aplicaie;
Script Perl
$dbh = DBI->connect ("DBI:mSQL:.
.sau...
$dbh = DBI->connect ("DBI:mysql:
...sau...
$dbh = DBI->connect ("DBI:Pg:...
Nivel
de interfa cu baza de date;
Nivelul driverului
pentru baze
de date

Nivelul
SGBDR
i_________
Figura 5.1 Arhitectura DBI.
Suportul MySQL pentru DBI este furnizat de ctre distribuia Msql-Mysql-modules. Acest modul opereaz la
nivelul DBD. Dup cum putei intui din numele distribuiei i de asemenea din figura 5.1, este posibil ca un
driver s furnizeze suport pentru mai multe sisteme de gestiune a bazelor de date relaionale. Iniial, distribuia
Msql-Mysql-modules lusese scris pentru mSQL, apoi extins ulterior i pentru MySQL. Acest fapt reflecta
asemnrile dintre interfeele API scrise n C pentru mSQL i MySQL. Din moment ce interfaa API scris n C
pentru MySQL a fost proiectat asemntor cu interfaa API n C pentru mSQL, era logic s se extind driverul
pentru baze de date mSQL (care folosete interfaa API pentru mSQL scris n C) astfel nct acesta s lucreze cu
MySQL.
Arhitectura DBI v permite s scriei aplicaii ntr-o manier relativ general. Cnd scriei un script DBI, folosii
un set standard de apeluri. Stratul DBI invoc driverul adecvat de la nivelul DBD pentru rezolvarea cerinelor
dumneavoastr, iar driverul se ocup de aspectele specifice ale comunicrii cu serverul specific de baze de date
pe care
226
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
dorii s-1 folosii. Nivelul DBD transmite datele returnate de server napoi ctre nivel| DBI, care prezint datele
aplicaiei dumneavoastr. Forma datelor este consecven^ indiferent de sistemul de baze de date din care au
provenit datele.
Rezultatul este o interfa care, din punctul de vedere al creatorului aplicaiei, ase diferenele ntre motoarele de
baze de date, dar lucreaz cu o mare varietate de motoa cu un numr egal cu acela al driverelor. DBI asigur o
interfa consecvent cu client care mrete portabilitatea permindu-v s obinei accesul la fiecare baz de
date nt manier uniform.
Singurul aspect al redactrii scripturilor care este n mod obligatoriu specific bazei de < apare la deschiderea unei
baze de date. Cnd stabilii conexiunea, indicai driverul pe i l folosii. De exemplu, pentru a folosi o baz de
date MySQL, v conectai astfel:
$dbh = DBI->connect ("DBI:mysql:..."); Pentru a folosi n schimb Postgres sau mSQL, v conectai astfel:
$dbh = DBI->connect ("DBI:Pg:...");
$dbh = DBI->connect ("DBI:mSQL:..."); Dup ce ai stabilit conexiunea, nu trebuie s mai facei nici o referire
specific la driy, Lsai rezolvarea detaliilor specifice bazelor de date n seama modulului DBI i a driver
Aa stau lucrurile, cel puin teoretic. Totui, exist cel puin doi factori care submine portabilitatea scripturilor
DBI:
Implementrile SQL difer ntre motoarele SGBDR i este perfect posibil s se pentru un motor programe SQL

pe care alt motor nu le poate nelege. Dac prc mul dumneavoastr SQL este suficient de general, scripturile
dumneavoastr vor i mod corespunztor, portabile de la un motor la altul. Dac programul dumnea\ tr SQL este
dependent de motor, scripturile vor fi de asemenea dependente de mol De exemplu, dac folosii instruciunea
SHOW TABLES specific sistemului MySC scriptul dumneavoastr nu va funciona cu alte sisteme de baze de
date.
Modulele DBD furnizeaz deseori tipuri de informaii specifice diferitelor motoare, ] tru a permite creatorilor
de scripturi s foloseasc anumite caracteristici ale sistemeloi baze de date. De exemplu, modulul DBD pentru
MySQL asigur o modalitate de; la proprietile coloanelor prin rezultatul unei interogri, precum lungimea m
fiecrei coloane, caracterul numeric sau ne-numeric al coloanelor etc. Aceste propr nu trebuie s aib vreun
analog n alte sisteme de baze de date. Caracteristicile spe modulului DBD sunt antitetice n raport cu
portabilitatea, iar prin utilizarea ngreunat utilizarea n alte sisteme de baze de date a unui script scris pentru
MySC
n ciuda potenialului acestor doi factori de a face din scripturile dumneavoastr ele specifice sistemelor de baze
de date, mecanismul DBI pentru furnizarea acces bazele de date ntr-o manier abstract reprezint un mijloc
rezonabil de rea portabilitii. Este la latitudinea dumneavoastr s decidei n ce msur dorii s l ficiai de
acest avantaj.
1 Cu toate acestea, vei descoperi c n capitolul 7, Interfaa API pentru Perl DBI", nu se : multe eforturi pentru
a evita construciile specifice sistemului MySQL furnizate de moduluN pentru MySQL. Aceasta deoarece trebuie
s tii ce anume reprezint construciile respective, j a decide personal dac le vei folosi sau nu. - N.A.
Capitolul 5 Introducere n programarea MySQL
227
Interfaa API pentru PHP
Ca i Perl, PHP este un limbaj de scripting. Spre deosebire de Perl, PHP este conceput n mai mic msur ca
limbaj de uz general dect ca limbaj pentru scrierea aplicaiilor Web. Interfaa API pentru PHP este folosit mai
ales ca mijloc pentru nglobarea scripturilor executabile n paginile Web. Acest fapt faciliteaz dezvoltatorilor
Web scrierea de pagini cu un coninut generat dinamic. Cnd un browser client trimite o cerere de pagin PHP
unui server Web, PHP execut toate scripturile pe care le gsete n pagin i le nlocuiete cu datele de ieire ale
acestora. Rezultatul este trimis browserului. Din acest motiv, pagina care apare efectiv n browser difer n
funcie de circumstanele n care a fost solicitat. De exemplu, cnd urmtorul script PHP scurt este nglobat ntro pagin Web, afieaz adresa IP a gazdei care a solicitat pagina:
<?php echo $REMOTE_ADDR; -?>
Ca o aplicaie mai interesant si mai puin banal, putei folosi un script pentru a furniza vizitatorilor informaii
de ultim moment, bazate pe coninutul bazei dumneavoastr de date. Exemplul urmtor prezint un script
simplu, cum este cel care ar putea fi folosit n situl Web al Ligii istorice. Scriptul emite o interogare pentru a
determina numrul curent de membri ai Ligii i l raporteaz persoanei care viziteaz situl (n cazul producerii
unei erori, scriptul pur si simplu nu raporteaz nici un numr.):
<HTML>
<HEAD>
<TITLE>Liga istorica americana</TITLE>
</HEAD>
<BODY>
Semnificaia abrevierilor DBI i DBD
Dei nivelul DBI este independent de sistemul de baze de date, iar nivelul DBD este dependent de acest sistem,
nu aceasta este semnificaia abrevierilor DBI, respectiv DBD2. Sensul lor este "database interface" (interfa cu
baza de date), respectiv "database drivef (driver pentru baze de date).
<P>Bine ai venit la situl Web al Ligii istorice.
<?php
$link = @mysql_pconnect ("pit-viper.snake.net", "paul1
or exit(); mysql_select_db ("samp_db")
or exit(); Sresult = mysql_query ("SELECT COUNT(*) FROM membru")
or exit(); if ($row = mysql_fetch_array ($result))
echo "<P>In prezent, Liga are " . $row[0] . " membri mysql_free_result ($result); ?> </BODY></HTML>
secret")
In sensul c DBI se mai poate abrevia (eronat) sub forma database independent (independent de sistemul de baze
de date), iar DBD se poate interpreta (tot eronat) sub forma database dependent (dependent de sistemul de baze
de date) - N.T.
228
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
n mod caracteristic, scripturile PHP arat ca pagini HTML cu scripturi nglobate n etichetele <?php i ?>. O
pagin poate conine mai multe scripturi. Acest proced| furnizeaz o abordare extrem de flexibil pentru
dezvoltarea scripturilor. De exemp dac dorii, putei scrie o pagin HTML normal pentru a construi cadrul

general' paginii, dup care adugai mai trziu coninutul de scripturi al paginii.
PHP nu face nici un efort de a unifica interfaa cu diferite motoare de baze de date,; cum procedeaz DBI. n
schimb, interfaa cu fiecare motor seamn foarte mult l interfaa pentru biblioteca C corespunztoare care
implementeaz interfaa API de sczut pentru motorul respectiv. De exemplu, numele funciilor PHP pe care le
folc pentru a obine acces la MySQL din interiorul scripturilor PHP sunt foarte asemna toare cu numele
funciilor din biblioteca client C pentru MySQL.
Alegerea unei interfee de programare a aplicaiilor
Aceast seciune conine ndrumri de ordin general, pentru a v ajuta s alegei o in fa API pentru diferitele
tipuri de aplicaii. Sunt comparate funcionalitile interfe API pentru C, DBI i PHP, pentru a v oferi o idee cu
privire la avantajele i dezav! tajele lor relative, precum i pentru a indica momentul oportun al alegerii uneia sau
alteia dintre interfee.
Probabil c ar trebui s art, mai nti, c nu pledez pentru utilizarea vreunuia dini aceste limbaje n detrimentul
altora. Le folosesc pe toate, dei am preferinele mele*| dumneavoastr vei avea propriile preferine, aa cum le
au si cei care au examinat: nuscrisul acestei cri. De fapt, unul dintre recenzori a fost de prere c ar trebui s j
un accent mai mare pe importana limbajului C pentru programarea n MySQL, n i ce altul credea c ar fi cazul
s critic zdravn programarea n C i s descurajez utiliz acestui limbaj! Va trebui s cntrii factorii discutai n
aceast seciune si s ajungej propriile dumneavoastr concluzii.
n alegerea dumneavoastr privind interfaa API de selectat pentru ndeplinirea anumite sarcini trebuie s inei
cont de un numr de consideraii:
Mediul de execuie scontat. Contextul n care v ateptai s fie folosit aplicaia;|
Performane. Eficiena derulrii aplicaiilor atunci cnd sunt scrise n limbajul ir feei API.
Simplitatea dezvoltrii. Uurina scrierii aplicaiilor determinat de interfaa de limbajul aferent acesteia.
Portabilitate. Dac aplicaia se va folosi sau nu pentru sisteme de baze de date ; dect MySQL. Fiecare din aceti factori va fi examinat pe larg n expunerea urmtoare. Reinei ci factori interacioneaz. De
exemplu, putei dori o aplicaie care se desfoar bin^ la fel de important poate fi utilizarea unui limbaj care v
permite s dezvoltai aplicaia, chiar dac nu se deruleaz att de eficient.
Capitolul 5 Introducere n programarea MySQL
229
Mediul de execuie
Cnd scriei o aplicaie, n general avei o oarecare idee cu privire la mediul n care se va folosi aceasta. De
exemplu, poate fi un program de generare a rapoartelor pe care l invocai din interpreter, respectiv un program
de sumar al contabilitii furnizorilor, care ruleaz ca sarcin a utilitarului cron la sfritul fiecrei luni. n
general, comenzile rulate din interpreter sau din utilitarul cron sunt de sine stttoare si nu pun prea multe probleme mediului de execuie. Pe de alt parte, putei scrie o aplicaie care urmeaz a fi invocat de un server Web.
Un asemenea program poate fi capabil de a extrage tipuri de informaii foarte exacte din mediul su de
dezvoltare, de genul: Ce browser folosete clientul? Care au fost parametrii introdui ntr-un formular de
solicitare a abonrii la o list de coresponden? A furnizat clientul parola corect pentru accesul la informaiile
legate de personalul nostru?
Fiecare limbaj API este mai mult sau mai puin adecvat pentru scrierea de aplicaii n aceste medii diferite:
C este un limbaj de uz general, deci, n principiu, poate fi folosit la orice, n practic, tendina este de a se
utiliza limbajul C pentru programe autonome, nu pentru programarea n Web. Un motiv, probabil, este acela c n
C prelucrarea textelor i gestiunea memoriei sunt mai dificile dect n Perl sau PHP, limbaje folosite pe scar
mare n aplicaiile Web.
Perl, ca i C, este adecvat pentru scrierea de programe autonome. Totui, se ntmpl ca Perl s fie deosebit de
util si pentru dezvoltarea siturilor Web, de exemplu prin utilizarea modulului CGI.pm. Aceasta face din Perl un
limbaj util pentru scrierea aplicaiilor care stabilesc o legtur ntre MySQL i Web. O asemenea aplicaie poate
interfaa cu Web-ul prin intermediul modulului CGI.pm si poate interaciona cu MySQL cu ajutorul modulului
DBI.
PHP este destinat, din proiectare, pentru scrierea aplicaiilor Web, deci reprezint, n mod evident, limbajul cel
mai propice pentru Web. Mai departe, accesul la bazele de date este una dintre cele mai puternice caracteristici
ale limbajului PHP, deci acesta constituie opiunea natural pentru aplicaiile Web care execut operaii legate de
MySQL. Este posibil utilizarea limbajului PHP ca interpreter autonom (de exemplu pentru execuia scripturilor
din shell3), dar nu este folosit foarte frecvent n acest mod.
Date fiind aceste consideraii, C i Perl sunt cele mai eligibile limbaje dac dorii s scriei o aplicaie autonom.
Pentru aplicaiile Web, Perl si PHP sunt cele mai adecvate. Dac trebuie s scriei aplicaii de ambele tipuri, dar
nu cunoatei nici unul din limbajele respective si dorii s nvai ct mai puin posibil, Perl poate fi alegerea
dumneavoastr cea mai bun.
Am folosit aici termenul shell n detrimentul traducerii sale uzuale (interpreter) pentru a nu crea o confuzie cu
interpretorul PHP despre care se discut n paragraful respectiv. - N.T.
230
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL

Performan
Dac sunt identice din toate celelalte puncte de vedere, n general preferm ca aplicaii noastre s ruleze ct mai
rapid posibil. Totui, importana efectiv a performanei tis s fie corelat cu frecvena de utilizare a unui
program. Pentru un program pe rulai o dat pe lun, n timpul nopii, sub forma unei sarcini a utilitarului cron,
perfcijj manta nu este un factor chiar att de important. Dac rulai un program de mai mu ori pe secund ntr-un
sit Web puternic solicitat, fiecare frm de ineficient pe cant eliminai poate determina o diferen
semnificativ, n cazul din urm, performanj joac un rol important n utilitatea i atractivitatea sitului
dumneavoastr. Un sit Ic! este agasant pentru utilizatori, indiferent de coninutul su, iar dac situl reprezint
surs de venit pentru dumneavoastr, o scdere a performanelor se convertete ntr-o reducere a veniturilor. Nu
vei putea onora un numr att de mare de simultan, iar vizitatorii dezgustai pur i simplu vor renuna i vor
pleca n alt parts.
Evaluarea performanelor este o problem complex. Cel mai bun indicator al compor aplicaiei dumneavoastr
atunci cnd este scris pentru o anumit interfa API este o scrie sub acea interfa i de a o folosi ca atare. Iar
cel mai bun test comparativ este c implementa aplicaia de mai multe ori, sub interfee API diferite, pentru a
examina i rentele ntre versiuni. Desigur, nu aceasta este situaia n realitate. Cel mai adesea, dorit v vedei scris
programul. Odat ce acesta funcioneaz, v putei gndi la ajustri dac < necesar s ruleze mai repede, s
foloseasc o cantitate mai redus de memorie sau prezint un alt aspect care trebuie mbuntit ntr-un alt mod.
Dar exist cel puin doi i tori care influeneaz performanele ntr-un mod relativ consecvent:
Programele compilate se execut mai rapid dect scripturile interpretate.
Pentru limbajele interpretate folosite ntr-un context Web, performanele sunt bune atunci cnd interpretorul
este invocat ca un modul care face pane din serve Web nsui, dect ca proces separat.
Limbaje compilate sau limbaje interpretate
Ca principiu general, aplicaiile compilate sunt mai eficiente, folosesc o cantitate "a redus de memorie si se
execut mai rapid dect o versiune echivalent a progra scris ntr-un limbaj de scripting. Acest lucru se
datoreaz suprasarcinii determinat interpretorul limbajului care execut scripturile. Deoarece C este compilat,
iar Pa PHP sunt interpretate, n general programele scrise n C vor rula mai rapid dect i turile Perl sau PHP.
Pentru un program puternic solicitat, C este deseori cea mai bun opiune. Client linie de comand mysql inclus
n distribuia MySQL este un bun exemplu n acest\
Exist, desigur, i factori care au tendina de atenua aceast deosebire clar. Unul din; este c, n general,
programele scrise n C sunt mai rapide, dar este foarte posibil s C programe ineficiente. Scrierea unui program
ntr-un limbaj compilat nu este un; automat spre un nivel mai ridicat de performan. Nu suntei scutit de a gndi
ceea ce; de fcut, n plus, diferena dintre programele compilate si cele interpretate este atenuat! o-aplicaie cu
scripturi i petrece majoritatea timpului executnd liniile de program dir j nele din biblioteca client MySQL
care sunt legate la motorul interpretorului.
Capitolul 5 Introducere n programarea MySQL
231 Versiuni autonome sau modulare ale interpretoarelor
limbajelor
Pentru aplicaiile bazate pe Web, interpretoarele limbajelor de scripting sunt folosite, de obicei, ntr-una din dou
forme (cel puin n cazul Apache, serverul Web pe care l vom folosi pentru a scrie aplicaiile Web):
Putei determina serverul Apache s invoce interpretorul ca proces separat. Cnd Apache trebuie s ruleze un
script Perl sau PHP, pornete programul corespunztor si i cere acestuia s execute scriptul. n acest caz, Apache
folosete interpretoarele ca programe CGI; cu alte cuvinte, execut comunicarea cu programele respective
folosind protocolul Common Gateway Interface (CGI).
Interpretorul poate fi folosit ca modul care este legat direct la binarul Apache si ruleaz ca parte a procesului
Apache nsui, n ceea ce privete serverul Apache, interpretoarele Perl i PHP iau forma modulelor mod_perl,
respectiv mod_php3.
Partizanii limbajelor Perl si PHP vor evidenia avantajele legate de vitez ale interpre-torului lor preferat, dar toi
sunt de acord c forma n care ruleaz interpretorul este un factor cu mult mai important dect limbajele n sine.
Ambele interpretoare ruleaz mult mai rapid ca modul dect ca aplicaie CGI autonom.
Cu o aplicaie autonom, este necesar s pornii interpretorul de fiecare dat cnd urmeaz a fi executat un script,
deci creai o penalizare semnificativ privind suprasarcina de creare de proces. Cnd este folosit ca modul n
cadrul unui proces Apache care ruleaz deja, funcionalitile unui interpreter pot fi accesibile instantaneu din
paginile dumneavoastr de Web. Acest fapt determin o cretere substanial a performanelor prin reducerea
suprasarcinii i se convertete direct ntr-o cretere a capacitii de tratare a cererilor recepionate i de distribuire
rapid a acestora.
Penalizarea la pornire a interpretorului autonom are ca rezultat, n mod caracteristic, o performan cu minimum
un ordin de mrime mai redus dect cea a interpretorului sub form de modul. Costul necesar la pornirea
interpretorului este important mai ales dac avei n vedere faptul c servirea paginii Web implic, de regul,
tranzacii rapide cu un volum redus de prelucrri, nu tranzacii substaniale, cu un volum mare de prelucrri.
Dac pierdei mult timp cu pornirea i mai puin cu execuia scriptului, atunci majoritatea resurselor
dumneavoastr se irosesc. Este ca i cum ai pierde majoritatea zilei pregtindu-v pentru lucru, ajungei la birou

la ora 16 i apoi plecai acas la 17.


V putei pune ntrebarea de ce apar economii de timp la versiunile modul ale interpretoarelor, deoarece tot
trebuie s pornii serverul Apache. Motivul este acela c, atunci cnd Apache pornete, creeaz imediat un
rezervor de procese copil care vor fi folosite pentru rezolvarea cererilor recepionate. Cnd sosete o cerere care
implic execuia unui script, exist deja un proces Apache gata pregtit pentru a rezolva cererea. De asemenea,
fiecare instan de Apache deservete mai multe cereri, deci costul procesului de pornire se calculeaz n raport
cu un set de cereri, nu n raport cu o singur cerere.
232
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Cnd Perl si PHP sunt instalate n form modular (sub forma mod_perl i mod_ph care din ele se descurc mai
bine? Acest aspect constituie un subiect de controverse, n general se aplic urmtoarele linii directoare:
Perl convertete scriptul ntr-o form compilat intern; PHP nu realizeaz acealj conversie. Astfel, odat
scriptul analizat, Perl are tendina de a-1 executa oarecum m rapid, mai ales pentru ciclurile cu un mare numr de
iteraii.
mod_perl poate memora scripturile n cache, pentru a mri performana scripturii* care se execut n mod
repetat. Dac un script se afl n cache, Perl ncepe s-1 execu mai rapid, deoarece nu mai trebuie analizat din
nou. n caz contrar, PHP ncepe, execute mai rapid scriptul.
mod_perl are o amprent de memorie mai mare dect PHP; procesele Apache sunt mari dac mod_perl, i nu
mod_php3, este legat la server. PHP a fost proiectat sub siderentul c trebuie s coopereze cu alt proces si s
poat fi activat si dezactivat de multe ori pe durata de via a procesului respectiv. Perl a fost proiectat pentru a
rula < linia de comand, ca program autonom, nu ca limbaj destinat a fi ncorporat ntr-un p ces de server Web.
Aceast caracteristic este cea care contribuie, probabil, la crestei dimensiunii amprentei de memorie; ca modul,
Perl pur i simplu nu ruleaz n mi su natural. Ali factori care contribuie la creterea dimensiunii amprentei de
menu sunt memorarea n cache a scripturilor si modulele Perl suplimentare pe care le folbsi scripturile, n ambele
situaii, n memorie este ncrcat o cantitate mai mare de p gram, care rmne acolo pe toat durata vieii
procesului Apache.
Indiferent de avantajele pe care Perl le poate avea n raport cu PHP n ceea ce privi viteza de execuie a
scripturilor, acestea sunt eliminate de PHP 4. Acesta este asemi tor cu PHP 3 n ceea ce privete funcionalitile
i interfaa, dar incorporeaz Zend, motor de interpretor cu performane superioare.
n orice caz, toi aceti factori au ca rezultat diferene de ordinul zecimilor de pro< ntre performanele
versiunilor de tip modul ale limbajelor Perl i PHP. Cel mai imp tant este s evitai interpretoarele autonome ori
de cte ori este posibil, indiferent de 1: bajul pe care l alegei.
Versiunea autonom a unui interpretor are un avantaj n raport cu omologul su n siune modul, n sensul c
putei determina rularea primei versiuni sub un alt identifis de utilizator. Versiunile modul ruleaz ntotdeauna
sub acelai identificator de utili: ca i serverul Web, care, n mod caracteristic, este un cont cu privilegii
minimale,, motive de securitate (de exemplu dac trebuie s putei citi sau scrie n fiiere protej; Putei combina
abordrile autonom si cea de tip modul, dac dorii, folosind versii modul n mod prestabilit, respectiv versiunea
autonom pentru situaii n care este rtj sar ca scripturile s ruleze cu privilegiile unui anumit utilizator.
Reducerea cerinelor de memorie ale modulului mod_perl
Exist tehnici care v permit s activai numai anumite procese Apache pentru mod_perl. suprasarcina
determinat de plusul de memorie apare numai la acele procese care execut scripturi'! Domeniul dedicat
modulului mod_perl din situl Web Apache conine o expunere pertinent a strategii pe care le putei alege.
(Pentru mai multe informaii, vezi http: / / perl. apache. org / guid
Capitolul 5 Introducere n programarea MySQL
233
Aceasta nseamn cu att mai mult c, ori de cte ori folosii Perl sau PHP, trebuie s ncercai s folosii
limbajul respectiv dintr-un modul Apache, nu s invocai un proces de interpreter separat. Rezervai utilizarea
interpretorului autonom numai pentru acele cazuri unde nu se poate folosi versiunea modul, cum sunt scripturile
care necesit privilegii speciale. Pentru aceste situaii, v putei prelucra scriptul folosind mecanismul Apache
suEXEC, pentru a porni interpretorul sub un anumit identificator de utilizator.
Timp de dezvoltare
Factorii pe care i-am descris anterior afecteaz performana aplicaiilor dumneavoastr, dar este posibil ca
eficiena brut a execuiei s nu fie unicul dumneavoastr scop. Timpul este de asemenea important, ca i
simplitatea n programare, deci un alt factor care trebuie luat n considerare la selectarea unei interfee API
pentru programarea n MySQL este rapiditatea cu care v putei desfura aplicaiile. Dac putei scrie un script
Perl ntr-un timp echivalent cu jumtatea intervalului necesar pentru a dezvolta echivalentul n C al programului
respectiv, atunci putei prefera s folosii interfaa API pentru modulul Perl DBI dect interfaa API pentru C,
chiar dac aplicaia rezultant nu ruleaz la fel de rapid. Deseori, este normal s fii mai puin interesat de timpul
de execuie a programului dect de timpul pe care l alocai scrierii acestuia, mai ales pentru aplicaiile care nu
sunt executate frecvent. O or din timpul dumneavoastr este cu mult mai valoroas dect o or din timpul
calculatorului4!
n general, limbajele de scripting v permit s punei pe roate" mult mai rapid un anumit program, mai ales

pentru elaborarea unui prototip al aplicaiei finite. Cel puin doi factori contribuie la aceasta.
Mai nti, limbajele de scripting au tendina de a furniza construcii de nivel mai nalt. Acest lucru v permite s
gndii la un nivel de abstractizare mai ridicat, astfel nct s v putei concentra asupra a ceea ce avei de fcut,
nu asupra detaliilor necesare. De exemplu, tablourile asociative (hash-urile) din Perl determin o economie de
timp semnificativ pentru ntreinerea datelor cu o relaie de tip cheie-valoare (cum sunt perechile identificator
elev - nume elev). Limbajul C nu dispune de o asemenea construcie. Dac ai fi dorit s implementai o
asemenea entitate n C, ar fi trebuit s scriei programe pentru rezolvarea mai multor detalii de nivel sczut,
legate de aspecte precum gestiunea memoriei i manipularea irurilor, programe pe care trebuie s le depanai.
Ori, aa ceva ia timp.
In al doilea rnd, ciclul de dezvoltare are mai puine etape pentru limbajele de scripting. In C, atunci cnd v
dezvoltai aplicaiile, trebuie s parcurgei testul obinuit de editare-compilare-testare. De fiecare dat cnd
modificai programul, trebuie s-1 compilai din nou nainte de a-1 testa. Cu Perl i PHP, ciclul de dezvoltare se
rezum la editare i testare, deoarece putei rula un script imediat dup fiecare modificare, fr compilare. Pe de
alt parte, compilatorul impune mai multe restricii asupra programului dumneavoastr, sub rorma unei verificri
mai stricte a tipurilor. Necesitatea disciplinei mai stricte impuse de compilator v poate ajuta s evitai hibe care
nu sunt att de uor de depistat n limbaje mai liberale, precum Perl sau PHP. Dac scriei greit un nume de
variabil n C, compile ne facem, ns, dac acea or din timpul calculatorului este o or din timpul clientului?
N.T.
234
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
latorul v va avertiza. PHP nu va face acest lucru, iar Perl nu v va avertiza dect dac cerei aceasta. Aceste
restricii mai puternice sunt valoroase mai ales dac aplicaiile di neavoastr devin mai mari i mai dificil de
ntreinut.
n general, compromisul este cel uzual dintre limbajele compilate i cele interpretat ntre timpul de dezvoltare i
performan: Dorii s dezvoltai programul folosind limbaj compilat, astfel nct s se execute mai rapid atunci
cnd ruleaz, dar s piere mai mult timp la scrierea programului? Sau dorii s scriei programul sub form d
script, pentru a-1 putea exploata n cel mai scurt timp, chiar i cu preul unei scade vitezei de execuie?
De asemenea, este posibil combinarea celor dou metode. Scriei un script dr ciorn" pentru a dezvolta rapid
un prototip al aplicaiei, n vederea testrii logicii j pentru a v asigura c algoritmii sunt coreci. Dac programul
se dovedete a fi utu"| este executat suficient de frecvent astfel nct performana s devin o problem, l pu
rescrie sub form de aplicaie compilat. Astfel, putei obine avantaje din ambele pa o creare rapid a
prototipului pentru dezvoltarea iniial a aplicaiei si un nivel de forman optim pentru produsul final.
ntr-un sens mai strict, nici una din interfeele API pentru Perl DBI i PHP nu of er w racteristici care nu exist
n biblioteca client C. Aceasta deoarece ambele interfee obin acces la MySQL prin legarea bibliotecii C pentru
MySQL la interpretoarele ' i PHP. Totui, mediul n care sunt nglobate caracteristicile sistemului MySQL foarte
diferit pentru C dect pentru Perl sau PHP. Gndii-v la unele dintre operaii necesare la interaciunea cu
serverul MySQL i ntrebai-v n ce msur fiecare limbajele API v poate ajuta la efectuarea acestora. Iat
cteva exemple:
Gestiunea memoriei, n C, vei lucra cu malloc() i f ree() pentru toate sarcinile i implic structuri de date
alocate dinamic. Perl i PHP execut aceste operaii autor De exemplu, dimensiunile tablourilor cresc automat,
iar irurile cu lungime dii
se pot folosi fr a v mai gndi la gestiunea memoriei.
Manipularea textelor. Perl are cele mai evoluate caracteristici n acest domeniu,1^ PHP l secondeaz
ndeaproape, n comparaie cu cele dou limbaje, C este fc rudimentar.
Desigur, n C v putei scrie propriile dumneavoastr biblioteci, care s ncapsuleze sa precum gestiunea
memoriei i prelucrarea textelor n funcii care s faciliteze ndeplifli sarcinii. Va trebui ns s depanai acele
funcii, i dorii ca algoritmii dumneavoastr; de asemenea, eficieni. Din ambele puncte de vedere, se poate
presupune c algorit Perl i PHP pentru aceste operaii sunt n general bine depanai si de o eficien rezor. din
moment ce au avut privilegiul" de a fi fost examinai de numeroase perechi de <! Putei economisi timp
beneficiind de timpul pe care alii 1-au investit n aceast sarcinTJj de alt parte, dac se ntmpl ca
interpretorul s aib o hib, s-ar putea s trebuia coabitai cu aceasta pn cnd problema este remediat. Cnd
scriei programe n C, i un control mai fin asupia comportrii programului dumneavoastr.)
Limbajele difer din punct de vedere al siguranei". Interfaa API pentru C fur interfaa de nivel cel mai sczut
cu serverul i aplic politica cea mai puin pretenfi Din acest motiv, furnizeaz sigurana cea mai precar. Dac
executai funcii API defj
Capitolul 5 Introducere n programarea MySQL
235
putei avea noroc si primii o eroare de nesincronizare" sau putei avea ghinion i programul dumneavoastr va
cdea. Scriptul dumneavoastr cade dac nu efectuai operaiile n ordinea corect, dar interpretorul nu se
defecteaz. O alt surs fertil de hibe din programele C care determin cderea sistemului este utilizarea
memoriei alocate dinamic si a pointerilor asociai acesteia. Perl i PHP se ocup automat de gestiunea memoriei,
deci este mult mai puin probabil ca scripturile dumneavoastr s-i dea duhul" datorit unor hibe de gestiune a

memoriei.
Timpul de dezvoltare este afectat de volumul de suport extern disponibil pentru un limbaj. Suportul extern pentru
C exist sub forma unor biblioteci container care ncapsuleaz funcii API n C pentru MySQL n rutine care sunt
mai uor de folosit. Bibliotecile care execut aceast operaie sunt disponibile att pentru C, ct i pentru C++.
Indiscutabil, Perl are cea mai mare cantitate de module add-on, sub form de module Perl (conceptual similare
cu modulele Apache). Exist chiar o infrastructur, conceput pentru a facilita localizarea si obinerea acestor
module (CPAN sau Comprehensive Perl Archive Network). Folosind module Perl, obinei acces la toate
categoriile de funcii fr a scrie nici mcar o linie de program. Dorii s scriei un script care s genereze un
raport dintr-o baz de date, care apoi s fie trimis cuiva sub form de fiier ataat la un e-mail? Procurai-v unul
dintre modulele MIME si vei dispune de o funcionalitate instantanee de generare a fiierelor ataate.
PHP nu dispune de aceeai cantitate de suport extern (ceea ce nu este surprinztor, dat fiind c este un limbaj mai
recent). Poate c modulul add-on cel mai bine cunoscut este PHP Base Library (PHPLIB). S presupunem c
scriei o aplicaie Web care trebuie s limiteze accesul la anumite pagini Web numai pentru utilizatorii autorizai,
n funcie de un anumit mecanism bazat pe nume i parol. Putei scrie programul de suport pentru aplicaia
respectiv n orice limbaj, dar, dac folosii PHP Base Library (PHPLIB), nu va trebui s v pierdei vremea
redescoperind roata. PHPLIB furnizeaz metode de autentificare i de asemenea v permite s urmrii
utilizatorii neautorizai pe parcursul unei sesiuni (o succesiune de deschideri de pagin de la un client dat, tratate
ca pri ale unei singure vizite logice). De asemenea, putei atribui permisiuni utilizatorilor, ceea ce v permite s
efectuai operaii precum definirea unor utilizatori administrativi, care dispun de mai multe privilegii.
Portabilitate
Problema portabilitii este legat de uurina cu care un program scris pentru a obine accesul la motorul
MySQL poate fi modificat astfel nct s foloseasc un alt motor. Acesta poate fi un aspect cruia nu-i acordai
nici o importan. Totui, cu excepia cazului n care avei caliti de vizionar i afirmai Niciodat nu voi folosi
acest program cu un alt sistem de baze de date dect MySQL", poate fi riscant: s presupunem c v schimbai
serviciul i dorii s v folosii vechile programe, dar dac noul dumneavoastr patron folosete un alt sistem de
baze de date?
236
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Dac portabilitatea este o prioritate, trebuie s avei n vedere diferenele nete r interfeele API:
DBI asigur interfaa API cea mai portabil, deoarece independena de sistemul ij baze de date este un
deziderat explicit de proiectare pentru DBI.
PHP este mai puin portabil, deoarece nu furnizeaz acelai tip de interfa uniforc pentru diferitele sisteme de
baze de date ca i DBI. Apelurile de funcii PHP pent fiecare sistem de baze de date acceptat sunt asemntoare
cu apelurile corespunztc din interfaa de baz API pentru C. Exist o oarecare atenuare a diferenelor, dar,'i
puin, va trebui s modificai numele funciilor de manipulare a bazelor de date pe ci le invocai. De asemenea, sar putea s fii obligat s revizuii puin i logica aplicai dumneavoastr, deoarece interfeele cu diferitele
sisteme de baze de date funcioneaz toate n exact acelai mod.
Interfaa API pentru G asigur portabilitatea cea mai redus ntre sistemele de baze j date. Prin natura sa,
aceast interfa este proiectat i destinat special utilizrii^ MySQL.
Portabilitatea - sub forma independenei de sistemul de baze de date - este deosebit;) important cnd trebuie s
obinei acces la mai multe sisteme de baze de date din cad! aceleiai aplicaii. Aici pot fi incluse sarcini simple,
precum mutarea datelor dintr?| SGBDR n altul, respectiv operaii mai complexe, cum ar fi generarea unui
raport] funcie de informaii obinute de la un numr de sisteme de baze de date.
Att DBI, ct i PHP furnizeaz suport pentru accesul la mai multe motoare de baz date, deci v putei conecta
simultan, cu uurin, la servere pentru sisteme de bazef| date diferite, plasate chiar pe calculatoare diferite. Cu
toate acestea, DBI i PHP nu: la fel de adecvate pentru sarcini care implic regsirea i prelucrarea datelor din
multe sisteme de baze de date complet diferite. DBI este de preferat, deoarece folosiii singur set de apeluri de
acces, indiferent de sistemele de baze de date pe care le folc S presupunem c dorii s transferai date ntre
sistemele de baze de date M) mSQL si Postgres. Cu DBI, unica diferen ntre modurile de utilizare a celor treia
teme de baze de date este apelul DBI->connect() folosit pentru conectarea la fie server. Cu PHP, avei un script
mai complicat, care ncorporeaz trei seturi de ape pentru citire, respectiv trei seturi de apeluri pentru scriere.
Un caz extrem al aplicaiei cu baze de date multiple este scriptul c rash-me din dist MySQL, care testeaz
funcionalitile a numeroase programe server de baze de date < rite. Acest script este scris folosind DBI, care
reprezint opiunea evident pentru o; nea aplicaie, deoarece putei obine acces n acelai mod la toate sistemele
de baze de ol
CAPITOLUL 6
Interfaa API MySQL pentru C
MySQL furnizeaz o bibliotec client scris n limbajul de programare C, pe care o putei folosi pentru a scrie
programe client care obin accesul la bazele de date MySQL. Aceast bibliotec definete o interfa de
programare a aplicaiilor, care include urmtoarele faciliti:
Rutine de gestiune a conexiunii, pentru iniierea i terminarea unei sesiuni cu un server.

Rutine de construcie a interogrilor, de trimitere a acestora la server si de prelucrare a rezultatelor.


Funcii de raportare a strii si a erorilor, pentru determinarea motivului exact al erorii atunci cnd alte apeluri
de funcii din interfaa API pentru C eueaz.
Acest capitol v prezint modul de utilizare a bibliotecii client pentru scrierea propriilor dumneavoastr
programe. Unele dintre dezideratele de care vom ine cont sunt consecvena cu programele client existente din
distribuia MySQL, precum i caracterul modular i capacitatea de reutilizare a codului. Presupun c avei
cunotine despre programarea n C, dar am ncercat s nu v confund cu un expert n materie.
Capitolul dezvolt o serie de programe client ntr-o progresie simpl, de la foarte simple la programe mai
complexe. Prima parte a acestei progresii dezvolt cadrul pentru un schelet al unui program client, care nu face
dect s se conecteze i s se deconecteze de la server. Motivul este c, dei programele client MySQL sunt
scrise cu scopuri diferite, toate au un lucru n comun: stabilesc o conexiune cu serverul.
Vom construi scheletul n etape:
1. Scriem un program elementar de conexiune si ntrerupere a conexiunii (clieni).
2. Adugm logic de verificare a apariiei erorilor (client2).
3. Facem programul de conexiune modular i reutilizabil (clienta).
4. Adugm capacitatea de a obine parametri de conexiune (gazd, utilizator, parol) la rulare (client4).
Acest cadru este suficient de general i dumneavoastr l putei folosi drept baz pentru orice numr de programe
client. Dup ce-1 vom crea, vom face o pauz pentru a ne gndi la modul de manipulare a diverselor interogri.
La nceput, vom discuta despre modul de manipulare a anumitor instruciuni SQL codate hard (adic nglobate n
codul programului - N.T.), dup care vom crea un program care se poate folosi pentru prelucrarea mstruciunilor
arbitrare. Apoi, vom aduga programul de prelucrare a interogrilor la cadrul nostru de program client, pentru a
crea un alt program (clients) care este simi-tar clientului mysql.
238
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
De asemenea, vom lua n considerare (i vom rezolva) unele probleme comune, de ger Cum mi pot procura
informaii despre structura tabelelor mele?" sau Cum pot ins< imagini n baza mea de date?".
Capitolul de fa discut despre funcii i tipuri de date din biblioteca client numai msura necesitilor. Pentru o
list comprehensiv a tuturor funciilor si tipurilor, va Anexa F, Referin API C". Putei folosi anexa respectiv
ca referin pentru al cunotine privind orice component a bibliotecii client pe care ncercai s o folosii/!
Programele date ca exemplu pot fi descrcate din Internet, deci le putei ncerca dirc fr a fi necesar s le tastai.
Pentru instruciuni, vezi Anexa A, Obinerea i instala programelor".
Unde se gsesc exemplele
O ntrebare comun care se afl n lista de coresponden MySQL este: Unde pot gsi unele exen de programe
client scrise n C?" Desigur, rspunsul este: .Chiar aici, n cartea asta". Dar un fapt pe < muli au tendina s nu-l
ia n considerare este acela c distribuia MySQL conine numeroase progn client (mysql, mysqladmin i
mysqldump, de exemplu), din care majoritatea sunt scrise n* Deoarece distribuia este disponibil sub form de
cod surs, MySQL nsui v ofer o cantitate'. ficativ de exemple de programe client. Ca atare, dac nu ai
fcut-o pn acum, luai o distribuie n < surs si examinai programele din catalogul client. Programele client
MySQL aparin domeniului | i putei mprumuta linitit linii de cod din ele pentru propriile dumneavoastr
programe, ntre exemplele furnizate n acest capitol i programele client induse n distribuia MySQL, putei gsi
< similar cu inteniile dumneavoastr atunci cnd v scriei propriile programe, n acest caz, putei refolos) l de
program prin copierea unui program existent i modificarea sa. Trebuie s citii acest capitol i nelege modul de
funcionare a bibliotecii client. Reinei, totui, c nu este necesar s scriei ntotde toate programele, pornind de
la zero. (Vei observa c posibilitatea de reutilizare a codului este unul < scopurile urmrite n expunerea noastr
din acest capitol privind scrierea programelor.) Dac economisi o mare cantitate de munc pornind de la
realizrile unei alte persoane, cu att mai bine.
Procedura general pentru construirea programelor cliei
Aceast seciune descrie etapele necesare pentru compilarea i legarea unui program i folosete biblioteca client
MySQL. Comenzile pentru construirea clienilor sunt oa cum diferite de la un sistem la altul, iar dumneavoastr
va trebui s modificai pij comenzile prezentate aici. Totui, descrierea are un caracter general i trebuie s o pu
aplica aproape oricrui program client pe care l scriei.
Cerine elementare de sistem
Cnd scriei un program client MySQL n C, vei avea nevoie de un compilator evident. Exemplele prezentate
aici folosesc compilatorul gcc. De asemenea, vei nevoie de urmtoarele entiti n afar de propriile
dumneavoastr fiiere surs:
Fiierele antet MySQL
Biblioteca client MySQL
Capitolul 6 Interfaa API MySQL pentru C
239
Fiierele antet i biblioteca client MySQL constituie suportul pentru programarea clienilor. Acestea pot fi deja
instalate n sistemul dumneavoastr, n caz contrar, este nevoie s vi le procurai. Dac MySQL a fost instalat
dintr-o distribuie surs sau binar, suportul pentru programarea clienilor trebuie s fi fost deja instalat ca parte a

procesului de instalare a distribuiei. Dac MySQL a fost instalat din fiiere RPM, acest suport nu va exista dect
cu condiia ca fiierele RPM pentru dezvoltatori s fi fost deja instalate. Dac trebuie s instalai fiierele antet si
biblioteca MySQL, vezi Anexa A.
Compilarea i legarea programului client
Pentru a compila i a lega un program client, trebuie s specificai unde se gsesc fiierele antet i biblioteca
client MySQL, deoarece aceste componente, de obicei, nu sunt instalate n locaiile unde compilatorul i
programul de legare le caut n mod prestabilit. Pentru exemplul urmtor, s presupunem c locaiile fiierelor
antet i a bibliotecii client sunt usr/local/include/mysql, respectiv /usr/local/lib/mysql.
Pentru a arta compilatorului cum s gseasc fiierele antet MySQL, transmitei-i un argument
-I/usr/local/include/mysql atunci cnd compilai un fiier surs ntr-un fiier obiect. De exemplu, putei folosi o
comand ca aceasta:
% gcc -c -I/usr/local/include/mysql myclient.c
Pentru a indica programului de legare unde s gseasc biblioteca client i care este numele acesteia, transmitei
argumentele -L/usr/local/lib/mysql i -Imysqlclient atunci cnd legai fiierul obiect, pentru a produce un fiier
binar executabil, dup cum urmeaz:
% gcc -o myclient rayclient.o -L/usr/local/lib/mysql -Imysqlclient n cazul n care clientul dumneavoastr este
alctuit din mai multe fiiere, denumii toate fiierele obiect n comanda de legare. Dac etapa de legare
genereaz o eroare legat de imposibilitatea de a gsi funcia floor(), legai biblioteca de funcii matematice prin
adugarea opiunii -Im la sfritul comenzii:
% gcc -o myclient myclient.o -L/usr/local/libJmysql -Imysqlclient -Im Mai poate fi necesar i adugarea altor
biblioteci. De exemplu, poate vei avea nevoie de -Isocket -Ini pe sistemele Solaris.
Dac nu folosii make pentru construirea programelor, v propun s nvai s folosii aceast comand, astfel
nct s nu fii obligat s tastai manual o mulime de comenzi pentru construirea programelor. S presupunem c
avei un program client, denumit myclient, care const din dou fiiere surs, main. c i aux. c, i un fiier antet,
denumit myclient. h. O comand Makefile simpl pentru construirea acestui program se poate prezenta astfel:
CC = gcc
INCLUDES = -I/usr/local/include/mysql
LIBS = -L/usr/local/lib/mysql -Imysqlclient
all: myclient
main.o: main.c myclient.h
$(CC) -c $(INCLUDES) main.c aux.o: aux.c myclient.h
Continuare
240
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Continuare
$(CC) -c $(INCLUDES) aux.c
myclient: main.o aux.o
$(CC) -o myclient main.o aux.o $(LIBS)
clean:
rm -f myclient main.o aux.o Dac n sistemul dumneavoastr este necesar legarea bibliotecii de formule
matematici modificai valoarea parametrului LIBS, adugnd -Im la sfrit:
LIBS = -L/usr/local/lib/mysql -Imysqlclient -Im Dac avei nevoie i de alte biblioteci, cum sunt -Isocket sau
-Ini, adugai-le i acestea la opiunea LIBS.
Folosind Makefile, v putei reconstrui programul ori de cte ori modificai vreuna din fiierele surs, prin
simpla tastare a expresiei "make". Este un procedeu mai simplu i puin supus la erori dect dac tastai o
comand gcc lung.
Client l - Conectarea la server
Primul nostru program client MySQL este ct se poate de simplu: se conecteaz la un se se deconecteaz i i
ncheie execuia. Acest program nu este foarte util n sine, dar tret s tii cum s efectuai operaiile respective,
deoarece, nainte de a putea exploata efectiv^ orice mod o baz de date MySQL, trebuie s firi conectat la un
server. Aceasta este o ope ie att de comun, nct vei folosi programul pe care l creai pentru a stabili o
conexul la fiecare client pe care l vei scrie. De asemenea, aceast sarcin ne permite s ncepe la ceva simplu.
Putem extinde ulterior programul client, pentru a executa operaii utile. ;|
Sursa pentru primul nostru program client, clieni, este compus dintr-un singur fiii clieni.c:
/* client!.c */
^include <stdio.h> ^include <mysql.h>
#define def_host_name NULL #define def_user_name NULL
tfdefine def_password NULL tfdefine def_db_name NULL
MYSQL *conn;
/* gazda la care se va stabili conexiuni (valoare prestabilita = localhost)
/* nume utilizator (valoare

prestabilita = numele dumneavoastr )J de deschidere a sesiunii de lucru)


/* parola (valoare prestabilita = nici. $ una) */
/* baza de date de utilizat (valoare prestabilita = nici una) */
/* pointer spre variabila de tratare a conexiunii */
Capitolul 6 Interfaa API MySQL pentru C
241
int
main (int argc, char *argv[J)
{
conn = mysql_init (NULL); mysql_real_connect ( conn,
def_host_name,
def_user_name, def ^password, def_db_name, O,
NULL,
0);
mysql_close (conn); exit(O);
/* pointer spre variabila de
tratare a conexiunii */ /* gazda la care se va stabili
conexiunea */
/* numele utilizatorului */ /* parola */
/* baza de date de utilizat */ /* port (se va folosi valoarea
prestabilita) */ /* soclu (se va folosi
valoarea prestabilita) */ /* indicatoare (nici unul) */
Fiierul surs ncepe prin a include stdio.h i mysql.h. Clienii MySQL pot include i alte fiiere antet, dar, n
general, acestea dou constituie minimul necesar.
Valorile prestabilite pentru numele gazdei, numele utilizatorului, parola i numele bazei de date sunt codate hard
n program, pentru simplitate. Ulterior, vom parametriza aceste valori, astfel nct dumneavoastr s le putei
specifica n fiiere cu opiuni sau n linia de comand.
Funcia main ( ) a programului iniiaz si ncheie conexiunea cu serverul. Stabilirea unei conexiuni este un
proces compus din dou etape:
1. Apelarea funciei mysql_init() pentru a obine o variabil de tratare a conexiunii. Tipul de date MYSQL este o
structur care conine informaii despre o conexiune. Variabilele de acest tip se numesc variabile de tratare a
conexiunii. Cnd transferai o valoare NULL funciei mysql_init( ), aceasta aloc o variabil MYSQL, o
iniializeaz i returneaz un pointer la aceasta.
2. Apelarea funciei mysql_real_connect() pentru a stabili o conexiune cu serverul. Funcia
mysql_real_connect( ) ia o mulime de parametri:
Un pointer spre variabila de tratare a conexiunii. Acesta trebuie s fie NULL; trebuie s fie valoarea returnat
de my sql_init ( ) ;
Gazda serverului. Dac specificai NULL sau gazda "localhost", clientul se conecteaz la serverul care ruleaz
pe gazda local, folosind un soclu UNIX. Dac specificai un nume al gazdei sau o adres IP a gazdei, clientul se
va conecta la gazda specificat folosind o conexiune TCP/IP.
n Windows, comportarea este similar, cu deosebirea c n locul soclurilor UNIX se folosesc conexiuni TCP/IP,
(n Windows NT, nainte de TCP/IP se ncearc o conexiune folosind un canal denumit, dac gazda este NULL.)
242
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Numele de utilizator i parola. Dac numele este NULL, biblioteca client i serverului numele dumneavoastr de
deschidere a sesiunii de lucru, parola este NULL, nu se va trimite nici o parol.
Numrul portului si fiierul soclu. Acestea sunt specificate ca fiind O, resp tiv NULL, pentru a indica
bibliotecii client s-i foloseasc valorile prestabif Dac portul i soclul nu sunt specificate, valorile prestabilite
sunt deterr n conformitate cu gazda la care dorii s v conectai. Detaliile acestei raii sunt date n descrierea
funciei mysql_real_conriect() din Anexa F. j
Valoarea indicatorilor (flags). Aceasta este O, deoarece nu folosim nici u de opiuni de conexiune speciale.
Opiunile care sunt disponibile pentru; parametru sunt discutate mai detaliat n informaiile referitoare la
mysql_real_connect () din Anexa F.
Pentru a termina conexiunea, transmitei funciei mysql_close() un pointer la va de tratare a conexiunii. O
variabil de tratare a conexiunii care este alocat autor ctre mysql_init() este dealocat automat atunci cnd
transferai variabila mysql_close () pentru ncheierea conexiunii.
Pentru a ncerca programul clieni, compilai-1 i legai-1 folosind instruciunile pr ae anterior n capitolul de
fa pentru construcia programelor client, dup care :
% clieni
Programul se conecteaz la server, se deconecteaz i i ncheie execuia. Nu-i interesant, dar este un nceput.
Totui, nu este dect un nceput, debarece exiti <i neajunsuri semnificative:
Clientul nu execut nici un fel de verificare a apariiei erorilor, deci nu tii*1' funcioneaz sau nu!

Parametrii de conexiune (nume de gazd, nume de utilizator etc.) sunt codai l codul surs. Este mai bine s
permitei utilizatorului s-i redefineasc, prin sf carea parametrilor ntr-un fiier cu opiuni sau n linia de
comand.
Nici una din aceste probleme nu este dificil de rezolvat. Ne vom ocupa de amb urmtoarele cteva seciuni.
Client 2 - Adugarea logicii de verificare a apariiei ei
Cel de-al doilea client al nostru va fi asemntor cu primul, numai c va fi modific tru a lua n calcul
posibilitatea apariiei erorilor. Este un obicei frecvent ca n programare s se spun Verificarea apariiei erorilor
este lsat ca exerciiu pent tor", deoarece verificarea apariiei erorilor este - s o recunoatem - o mare plic Cu
toate acestea, prefer s promovez punctul de vedere conform cruia prc client MySQL trebuie s testeze
condiiile de eroare i s reacioneze la acestea c adecvat. Apelurile la biblioteca client care returneaz valori de
stare procedeaz J dintr-un anumit motiv, iar dac dumneavoastr le ignorai, o facei pe risc propris sfri fie
ncercnd s depistai probleme obscure care survin n programele du voastr datorit inexistenei unei verificri
a apariiei erorilor, fie utilizatorii prc lor dumneavoastr se vor ntreba de ce programele astea au luat-o razna,
fie;
Capitolul 6 interfaa API MySQL pentru C
243
S lum n considerare programul nostru clieni. Cum tii dac acesta s-a conectat sau nu la server? Ai putea
afla cutnd n jurnalul serverului evenimentele Connect i Quit, care corespund intervalului de timp n care s^-a
rulat programul:
990516 21:52:14
20 Connect
pauieibfcalhost on
20 Quit
>
Alternativ, putei vedea n schimb un mesaj Access denied (acces interzis):
990516 22:01:47
21 Connect
Access denied for user:
1pauieiocalhost'(Using password:NO)
Acest mesaj arat c nu a fost stabilita nici o conexiune. Din pcate, programul clieni nu ne spune care dintre
aceste dou rezultate s-a produs. De fapt, nu poate. Nu execut nici o verificare a apariiei erorilor, deci nu tie
nici el ce s-a ntmplat, n orice caz, categoric nu trebuie s examinai jurnalul pentru a afla dac ai reuit sau nu
s v conectai la server! S remediem chiar acum problema.
Rutinele din biblioteca client MySQL care returneaz o valoare indic, n general, reuita sau eecul ntr-unul din
urmtoarele dou moduri:
Funciile cu valori pointeri returneaz un pointer diferit de NULL pentru succes, respectiv NULL pentru eec.
(n acest context, NULL nseamn Un pointer C NULL" nu O valoare NULL dintr-o coloan MySQL".)
Dintre rutinele din biblioteca client pe care le-am folosit pn acum, mysql_init () i
mysql_real_connecrt<')returneaz ambele un pointer al variabilei de tratare a conexiunii pentru a indica succesul,
respectiv NULL pentru eec.
Funciile cu valori ntregi returneaz de obicei O pentru reuit i o valoare diferit de zero pentru eec. Este
important s nu se verifice existena unor anumite valori diferite de zero, cum este -1. Nu exist nici o garanie
c 6 funcie din biblioteca client returneaz o anumit valoare atunci cnd eueaz. Ocazional, putei vedea
programe mai vechi, care testeaz incorect o valoare returnat, astfel:
if (mysql_XXX{) == -1)
/* acest test este incorect */
fprintf (stderr, "s-antmplat ceva rau\n");
Acest test s-ar putea s funcioneze, dar s-ar putea s nu funcioneze. Interfaa API MySQL nu specific faptul c
orice eroare returnat diferit de zero va fi o anumit valoare, n afara

faptului c este diferit de zero. Testul trebuie scris astfel:


I
if (mysql_XXX())
/* acest test este corect */

fprintf (stderr, 's-a ntmplat ceva rau\n"); l


sau astfel:

if (mysql_XXX() 1= 0)
/* acest test este corect */ l
fprintf (stderr, "s-a ntmplat
ceva rau\n");
l
Cele dou teste surit echivalente; Dac examinai codul surs al sistemului MySQL nsui,

v?i observa c n general se folosete prima form a testului, care se scrie mai rapid.

Nu fiecare apel API returneaz o valoare. Cealalt rutin client pe care am folosit-o,

mysqi_ciose(), este una care nu returneaz nici o valoare. (Curn^e a putut $.eueze?

Iar dac a euat, ce-mi pas mie? Oricum ari terminat conexiunea.)
244
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Cnd un apel la o bibliotec client eueaz i avei nevoie de mai multe informaii des; eec, dou apeluri de
funcii din interfaa API sunt utile. mysql_error () returneaz ir care conine un mesaj de eroare, iar
mysql_errno() returneaz un cod numeric eroare. Trebuie s apelai aceste funcii imediat dup apariia unei
erori, deoarece, d; emitei un alt apel API care returneaz o stare, toate informaiile de eroare pe care le V( primi
de la funciile mysql_error()sau mysql_errno() se vor referi la apelul ulterior, j
n general, pentru utilizatorul unui program irul de eroare este mai edificator decj codul de eroare. Dac vei
raporta numai una din cele dou informaii, ar fi bine < aceasta s fie irul. Din motive de completitudine,

exemplele din acest capitol raport ambele valori.


Lund n considerare discuia anterioar, vom scrie al doilea program client, client
Acesta este similar cu clieni, dar conine n plus un program adecvat de verificat-l
apariiei erorilor. Fiierul surs, client2.c, se prezint astfel:
/* client2.c */
^include <stdio.h> #include <mysql.h>
#define def_host_name NULL define def_user_name NULL
tfdefine def_password NULL #define def_db_name NULL
/* gazda la care se va stabili
conexiunea(valoare
prestabilita = localhost) */
f| /* nume utilizator (valoare
'J
prestabilita = numele dumneavoastr
de deschidere a sesiunii de lucru) *fi l* parola (valoare prestabilita =
nici una) */ /* baza de date de utilizat (valoare
prestabilita = nici una) */
MYSQL *conn;
/* pointer spre variabila de tratare a conexiunii */
int
main (int argc, char *argv[J)
{
conn = mysqlJLnit (NULL) ;
if (conn == NULL)
fprintf (stderr, "mysql_init() ratat (probabil din lipsa
de memorie) \n"); exit(1);
if (mysql_real_connect (
conn,
/* pointer spre variabila de
tratare a conexiunii */
Capitolul 6 Interfaa API MySQL pentru C
245
def_host_name,
def_user_name, def_password, def_db_name, 0,
NULL,
0); == NULL)
/* gazda la care se va stabili
conexiunea */
numele utilizatorului */
parola */ /* baza de date de utilizat */
port (se va folosi valoarea
prestabilita) */
soclu (se va folosi
valoarea prestabilita) */
indicatoare (nici unul) */
/* /*
fprintf (stderr, "mysql_real_connect() failed: \nError %u (%s)\n",
mysql_errno(conn), mysql_error(conn)); exit(1);
mysql_close (conn); exit(O);
Logica de verificare a apariiei erorilor se bazeaz pe faptul c att mysql_init() ct i mysql_real_connect()
returneaz NULL dac eueaz. Reinei c, dei programul verific valoarea returnat a funciei mysql_init(),
dac aceasta eueaz nu este apelat nici o funcie de raportare a erorilor. Aceasta deoarece nu se poate
presupune c variabila de tratare a conexiunii va conine informaii utile atunci cnd mysql_init () eueaz. Prin
contrast, atunci cnd mysql_real_connect () eueaz, variabila de tratare a conexiunii nu mai reflect o conexiune
valid, dar conine informaii de eroare care pot fi transmise funciilor de raportare a erorilor. (Nu transmitei
variabila de tratare altor rutine client! Deoarece acestea presupun, n general, c acea conexiune este valid,
programul va suferi o cdere.)
Compilai si legai programul client2, dup care ncercai s-1 rulai:
% client2
Dac programul client2 nu genereaz nici un fel de date de ieire (aa cum s-a artat anterior), nseamn c s-a
conectat cu succes. Pe de alt parte, s-ar putea s vedei urmtorul rezultat:
% clienta
mysql_real_connect() failed:
Error 1045 (Access denied for user: 'paulSlocalhost'(Using password: NO)) Acest rezultat arat c nu a fost

stabilit nici o conexiune i v permite s aflai motivul. De asemenea, nseamn c nici primul nostru program,
client 1, nu a reuit s se conecteze la server! (La urma urmelor, client! a folosit aceiai parametri de.conexiune.)
La momentul respectiv nu am tiut acest lucru, deoarece clieni nu s-a deranjat s verifice apariia erorilor.
client2 execut aceast verificare, deci ne poate anuna dac se ntmpl ceva grav. De aceea trebuie ntotdeauna
s testai valorile returnate de funciile API.
Rspunsurile la ntrebrile din lista de coresponden pentru MySQL au frecvent legtur cu verificarea apariiei
erorilor, ntrebrile caracteristice sunt De ce programul meu cade
246
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
atunci cnd emite aceast interogare?" sau Cum se face c interogarea mea nu returne nici un rezultat?", n
multe situaii, programul n chestiune nu a verificat dac acea conexiu a fost sau nu stabilit cu succes nainte de
a emite interogarea, respectiv nu a verificat pen a se asigura c serverul a executat cu succes interogarea nainte
de a ncerca s regse rezultatele. Nu facei greeala de a crede c fiecare apel la biblioteca client reuete.
Celelalte exemple din acest capitol execut verificarea apariiei erorilor, iar dumneavoa trebuie s procedai la
fel. S-ar putea s vi se par mai mult munc, dar pe termen Iu este de fapt mai puin, deoarece v pierdei mai
puin timp cu depistarea probleme subtile. Voi folosi aceeai procedur de verificare a apariiei erorilor n
capitolele i Interfaa API pentru Perl DBI", respectiv 8, Interfaa API pentru PHP".
Acum, s presupunem c ai primit un mesaj Access denied cnd ai rulat prog client2. Cum putei remedia
problema? O posibilitate este de a modifica liniile #def i care conin numele gazdei, numele utilizatorului i
parola, insernd valori care v pe s obinei accesul la serverul dumneavoastr. Acest procedeu poate fi benefic,
n se c mcar vei reui s stabilii o conexiune. Dar valorile sunt n continuare codate ha programul
dumneavoastr. Sunt mpotriva acestei metode, mai ales n ceea ce prive valoarea parolei. S-ar putea s credei
c parola devine ascuns atunci cnd compilai pt gramul n form binar, dar nu mai este ascuns deloc dac
cineva poate rula strings! programul dumneavoastr. (Ca s nu mai vorbim de faptul c orice persoan cu acces <
citire la fiierul dumneavoastr surs poate obine parola fr s se osteneasc deloc.)^
Vom aborda problema accesului n seciunea Client 4 - Obinerea parametrilor*, conexiune la rulare". Mai nti,
a dori s v prezint alte metode de scriere a progra lui de conexiune.
Client 3 - Imprimarea unui caracter modular asupra programului de conexiune
Pentru cel de-al treilea client, clienta, vom crea un program de conectare i decone modular, prin ncapsularea sa
n funciile do_connect (), respectiv do_disconnect (), < pot fi folosite cu uurin de mai multe programe client.
Aceast metod ofer o alt tiv la nglobarea literal a programului de conectare n funcia dumneavoastr m
Oricum, este o idee bun pentru orice program care nu se modific de la o aplica| alta. Inserai programul ntr-o
funcie accesibil din mai multe programe, n loc .d scrie n fiecare program. Dac remediai o hib sau dac
aducei funciei o mbunt| putei face modificarea o singur dat, iar toate programele care folosesc funcia vor
fi remediate sau vor putea beneficia de mbuntirea adus printr-o simpl recompu| De asemenea, unele
programe client sunt scrise de aa manier nct se pot cone deconecta de mai multe ori pe durata execuiei lor.
Este mult mai simplu s scriettl asemenea client, dac imprimai programului un caracter modular prin inseria
m melor de pornire si oprire n interiorul funciilor de conectare i deconectare.
Strategia de ncapsulare funcioneaz astfel: 1. Divizai programul comun n funcii container ntr-un fiier surs
separat, denuj common.c.
Capitolul 6 Interfaa API MySQL pentru C
247
2. Furnizai un fiier antet, common . h, care s conin prototipuri ale rutinelor comune.
3. Includei fiierul common . h n fiierele surs ale clienilor care folosesc rutine comune.
4. Compilai fiierele surs comune ntr-un fiier obiect.
5. Legai acel fiier obiect comun la programul dumneavoastr client.
Avnd n vedere aceast strategie, s construim funciile do_connect ( ) i do_disconnect ( ) .
Funcia do_connect ( ) nlocuiete apelurile la funciile my sql_init ( ) i mysql_real_con nect(), precum i programul de afiare a erorilor. Putei denumi funcia chiar
mysql_real connect (), cu deosebirea c nu-i transferai nici o variabil de tratare a
conexiunii. In schimb, do_connect() aloc i iniializeaz singur variabila, iar apoi
returneaz un pointer spre aceasta dup conectare. Dac do_connect ( ) eueaz, afieaz
un mesaj de eroare i returneaz NULL. (Astfel, orice program care apeleaz funcia
do_connect ( ) si obine o valoare returnat NULL i poate ncheia pur si simplu execuia,
fr a se mai deranja s afieze un mesaj.)
Funcia do_disconnect( ) preia un pointer spre variabila de tratare a conexiunii i apeleaz funcia mysql_close( ).
Iat liniile de program ale fiierului common . c:
#include <stdio.h>
^include <mysql.h>
^include "common. h"
MYSQL *

do_connect(char *host_name, char *user_name, char *password,


char *db_name, unsigned int port_num,
char *socket_name, unsigned int flags)
MYSQL *conn
/* pointer spre variabila de tratare a conexiunii */
conn = mysql_init (NULL); /* aloca, iniializeaz variabila de
tratare a conexiunii */ if (conn == NULL)
{
fprintf (stderr, "mysql_init() failed\n"); return (NULL);
}
if (mysql_real_connect (conn, host_name, user_name, password, db_name, port_num, socket_name, flags) ==
NULL)
{
fprintf (stderr, "mysql_real_connect() failed: \nError %u (%s)\n",
mysql_errno(conn) , mysql_error(conn) ) ; return (NULL);
return(conn)
/* conexiunea a fost stabilita */
Continuare
248
Partea a ll-a Utilizarea interfeelor de programare ale sistemului MySQL
Continuare
void
do_disconnect (MYSQL *conn)
{
mysql_close(conn);
} Fiierul common.h declar prototipurile pentru rutinele din fiierul common.c:
MYSQL *
do_connect(char *host_name, char *user_name, char *password, char *db_name, unsigned int port_num, char
*socket_name, unsigned int flags);
void
do_disconnect (MYSQL *conn);
Pentru a obine accesul la rutinele comune, includei fiierul common. h n fiierele dr neavoastr surs. Reinei
c fiierul common.c include i fiierul common.h. Astfel/ definiiile de funcii din common. c nu corespund
declaraiilor din fiierul antet, vei pr imediat un avertisment de la compilator. De asemenea, dac modificai o
secvenial apelare din common. c fr a face schimbrile de rigoare n fiierul common. h, atunci < recompilai
common. c vei primi un avertisment de la compilator.
Este absolut normal s v ntrebai de ce s-a inventat o funcie container, i ami do_disconnect (), care execut
att de puine operaii. Este adevrat c do_disconned i mysql_close () sunt echivalente. Dar s presupunem c,
la un moment ulterior, c s facei o oarecare curenie suplimentar de fiecare dat cnd v deconectai, apelarea
unei funcii container asupra creia avei un control total, putei modif aceast funcie astfel nct s execute
operaiile pe care le dorii, iar modificrile int funciune n acelai mod pentru toate operaiile de deconectare pe
care le executai?! putei face acest lucru dac invocai direct funcia mysql_close().
Anterior, am afirmat c este benefic modularizarea" programelor frecvent folosite \ ncapsularea lor ntr-o
funcie care poate fi folosit de mai multe programe, respectiv \ mai multe locuri din interiorul unui singur
program. Paragraful precedent a oferit un i pentru aceast operaie, iar urmtoarele dou exemple vor furniza
justificri supliment
Exemplul 1. n versiunile MySQL anterioare seriei 3.22, apelul la funcia mysql_real_ nect () era uor diferit de
varianta actual: nu exista nici un parametru care s ir numele bazei de date. Dac dorii s folosii funcia
do_connect () cu o bibliotec i MySQL mai veche, acest lucru nu este posibil. Totui, este posibil modificarea;
do_connect () astfel nct s poat funciona cu instalri ale sistemului MySQL ant versiunii 3.22. Aceasta
nseamn c, prin modificarea funciei do_connect(), putei l nivelul de portabilitate al tuturor programelor care o
folosesc. Dac nglobai literal l gramul de conectare n fiecare client, trebuie s modificai fiecare client n parte.
Pentru a remedia funcia do_connect () astfel nct s poat lucra cu forma mai v< a funciei mysql_real_connect
(), folosii macroinstruciunea MYSQL_VERSION_ID, | conine numrul curent al versiunii MySQL. Funcia
do_connect() modif testeaz valoarea parametrului MYSQL_VERSION_ID i folosete forma corespunzt| a
funciei mysql_real_connect():
Capitolul 6 Interfaa API MySQL pentru C
249
MYSQL *
do_connect(char *host_name, char *user_name, char *password,
char *db_name, unsigned int port_num,
char *socket_name, unsigned int flags)

{
MYSQL *conn /* pointer spre variabila de tratare a conexiunii */
conn = mysql_init (NULL); /* aloca, iniializeaz variabila de
tratare a conexiunii */ if (conn == NULL) {
fprintf (stderr, "mysql_init() failed\n");
return (NULL);
} #if defined (MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 32200
/* versiunea 3.22 si versiunile ulterioare */ if (mysql_real_connect (conn, hostjiame, userjriame, password,
db_name, port_num, socket_name, flags) == NULL)
{
fprintf (stderr, "mysql_real_connect() failed: \nError %u (%s)\n",
mysql_errno(conn) , mysql_error(conn)) ; return(NULL);
}
#else
/* pentru MySQL anterior versiunii 3.22 */
if (mysql_real_connect (conn, hostjiame, user_name, password, port_num, socket_name, flags) == NULL)
{
fprintf (stderr, "mysql_real_connect() f ailed: \nError %u (%s)\n", mysql_errno(conn), mysql_error(conn));
return(NULL); } if (dbjiame != NULL) /* simularea efectului parametrului db_name */
{
if (mysql_select_db (conn, db_name) != 0)
{
fprintf (stderr, "mysql_select_db{) f ailed: \nError %u
(%s)\n", mysql_errno(conn), mysql_error(conn)) ; mysql_close(conn) ; return(NULL);
#endif
return (conn); /* conexiunea a fost stabilita */

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

  • Mysql 350
    Mysql 350
    Document28 pagini
    Mysql 350
    Lupu Adrian
    Încă nu există evaluări
  • Mysql 250
    Mysql 250
    Document29 pagini
    Mysql 250
    gabrielgabor22
    Încă nu există evaluări
  • Mysql 150
    Mysql 150
    Document30 pagini
    Mysql 150
    Lucian Musteata
    Încă nu există evaluări
  • Mysql 100
    Mysql 100
    Document32 pagini
    Mysql 100
    Виктор Которобай
    Încă nu există evaluări