Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Caracteristici esenţiale ale SGBD şi SGBC
1
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
CUPRINS TENDINŢE ACTUALE ÎN INDUSTRIA SGBD................................................................5 Sisteme de Gestiune a Bazelor de Date (SGBD)..............................................................5 Tranzacţii..........................................................................................................................5 Arhitecturi Client / Server.................................................................................................6 Sisteme deschise şi bd distribuite......................................................................................8 Baze de date distribuite.................................................................................................8 Programe interfaţă de acces..........................................................................................9 Medii de procesare paralelă..............................................................................................9 Arhitecturi fără partajare.............................................................................................10 Arhitecturi cu discuri partajate....................................................................................10 Arhitecturi cu memorie partajată................................................................................11 Patru tipuri de cuplare a procesoarelor: strânsă, lejeră, simetrică, şi asimetrică.........11 Procesarea paralelă a tranzacţiilor şi interogărilor .....................................................11 Procesarea paralelă a indexurilor şi a programelor utilitare........................................12 Sisteme orientate obiect..................................................................................................12 Gestiunea obiectelor persistente în arhitecturi client / server.....................................13 Un exemplu de bd orientată obiect..............................................................................14 Integrarea în Internet.......................................................................................................15 Cinci exemple de SGBD celebre.....................................................................................18 DATABASE2 (DB2) MVS / ESA versiunile 3 şi 4 ale IBM ....................................18 Oracle 7.1 al Oracle.....................................................................................................18 SQL Server 10.0 al Sybase.........................................................................................19 NonStop SQL / MP al Tandem...................................................................................19 CA-OpenIngres al Computer Associates....................................................................19 Comentarii şi referinţe bibliografice...............................................................................20 2. CONTROLUL CONCURENŢEI...................................................................................21 Lacăte..............................................................................................................................21 Cele două tipuri fundamentale de lacăte: partajabil şi exclusiv..................................21 Granularitatea..................................................................................................................22 Niveluri de izolare a lacătelor.........................................................................................23 Izolarea citirilor repetabile..........................................................................................23 Stabilitatea cursorului.................................................................................................23 Blocarea în două faze......................................................................................................24 Blocaje fatale...................................................................................................................25 Blocaje fatale globale în bd distribuite........................................................................25 Comentarii şi referinţe bibliografice...............................................................................26 Controlul concurenţei în DB2.....................................................................................26 Controlul concurenţei în NonStop SQL......................................................................27 Controlul concurenţei în Oracle..................................................................................28 Controlul concurenţei în SQL Server al Sybase.........................................................29 Controlul concurenţei în CA-OpenIngres...................................................................30 3. SALVĂRI ŞI RECUPERAREA DIN EROARE............................................................32 Jurnale de actualizări.......................................................................................................32 Refacerea şi “desfacerea” automată a actualizărilor.......................................................32 Puncte de verificare.........................................................................................................33 2
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Recuperarea din dezastre.................................................................................................35 Comentarii şi referinţe bibliografice...............................................................................35 Salvări şi recuperări în DB2........................................................................................35 Salvări şi recuperări în NonStop SQL.........................................................................36 Salvări şi recuperări în Oracle.....................................................................................36 Salvări şi recuperări în SQL Server al Sybase............................................................37 Salvări şi recuperări în CA-OpenIngres......................................................................38 4. SECURITATEA DATELOR..........................................................................................39 Privilegii..........................................................................................................................39 Codificarea datelor şi verificarea accesului....................................................................39 Ierarhia nivelurilor de acces utilizator în bd distribuite..................................................40 Comentarii şi referinţe bibliografice...............................................................................40 Securitatea datelor în DB2..........................................................................................40 Securitatea datelor în NonStop SQL...........................................................................40 Securitatea datelor în Oracle.......................................................................................41 Securitatea datelor în SQL Server...............................................................................41 Securitatea datelor în CA-OpenIngres........................................................................41 5. IMPUNEREA CONSTRÂNGERILOR DE INTEGRITATE........................................42 Integritatea domeniilor de valori.....................................................................................42 Integritatea referinţelor....................................................................................................42 Trăgaciuri........................................................................................................................43 Procesarea în două faze a terminării execuţiei tranzacţiilor............................................43 Comentarii şi referinţe bibliografice...............................................................................45 Impunerea constrângerilor în DB2..............................................................................45 Impunerea constrângerilor în NonStop SQL..............................................................46 Impunerea constrângerilor în Oracle...........................................................................46 Impunerea constrângerilor în SQL Server..................................................................46 Impunerea constrângerilor în CA-OpenIngres............................................................46 6. IMPLEMENTAREA FIŞIERELOR INDEX...............................................................47 Accesul “talmeş-balmeş” (“hash”)..................................................................................47 Arbori B+........................................................................................................................48 Memorarea grupată a tuplilor în pagini...........................................................................49 Comentarii şi referinţe bibliografice...............................................................................49 Fişiere index în DB2...................................................................................................50 Fişiere index în NonStop SQL....................................................................................50 Fişiere index în Oracle................................................................................................50 Fişiere index în SQL Server........................................................................................50 Fişiere index în CA-OpenIngres.................................................................................50 7. OPTIMIZAREA PROCESĂRII ŞI ACCESULUI LA DATE.....................................51 Optimizarea operatorului join.........................................................................................51 Implementarea “buclă în buclă” a joinului..................................................................51 Implementarea “sort/reuniune” a join-ului..................................................................51 Implementarea hibridă a joinului................................................................................52 Implementarea “talmeş-balmeş” a join-ului................................................................52 Implementarea folosind semijoin-uri în bd distribuite................................................52 Alte tipuri de optimizări ale procesării datelor...............................................................53 Folosirea mai multor fişiere index per tabelă: implementarea “index AND” şi “index OR” a selecţiilor................................................................................................................54 3
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Optimizarea accesului la date bazată pe reguli...............................................................55 Optimizarea accesului la date bazată pe costuri..............................................................55 Mecanisme de control a optimizării accesului la date....................................................55 Optimizarea globală a accesului în bd distribuite...........................................................56 Comentarii şi referinţe bibliografice...............................................................................57 Optimizarea în DB2....................................................................................................57 Optimizarea în NonStop SQL.....................................................................................58 Optimizarea în Oracle.................................................................................................58 Optimizarea în SQL Server.........................................................................................58 Optimizarea în CA-OpenIngres..................................................................................58 8. CATALOAGE DE META-DATE................................................................................59 Structura şi conţinutul cataloagelor.................................................................................59 Accesul utilizatorilor la cataloage...................................................................................59 Gestiunea cataloagelor în bd distribuite..........................................................................60 Comentarii şi referinţe bibliografice...............................................................................60 Cataloagele în DB2.....................................................................................................60 Cataloagele în NonStop SQL......................................................................................61 Cataloagele în Oracle..................................................................................................61 Cataloagele în SQL Server..........................................................................................61 Cataloagele în CA-OpenIngres...................................................................................61 9. INTERFEŢE DE PROGRAMAREA APLICAŢIILOR (API).....................................62 Interfeţe încorporate şi interfeţe apel..............................................................................62 SQL static şi dinamic. Proceduri memorate....................................................................62 Comentarii şi referinţe bibliografice...............................................................................63 API în DB2..................................................................................................................63 API în NonStop SQL..................................................................................................63 API în Oracle..............................................................................................................63 API în SQL Server......................................................................................................64 API în CA-OpenIngres................................................................................................64
4
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
TENDINŢE ACTUALE ÎN INDUSTRIA SGBD Sisteme de Gestiune a Bazelor de Date (SGBD) Sistemele de Gestiune a Bazelor de Date (SGBD) sunt programe care procesează datele privite ca resurse partajabile. Ele permit utilizatorilor structurarea datelor (conform unui model conceptual) în baze de date (bd) şi exploatarea acestora concurent, de către mai mulţi utilizatori simultan. Pentru aceasta, ele asigură mecanisme cel puţin pentru: • • • • •
memorarea (structurată a) datelor accesul la date protecţia datelor (la tentative de acces neautorizat) păstrarea integrităţii datelor recuperarea din erori.
SGBD sunt azi oferite pe o mare varietate de platforme de calcul, pornind de la calculatoarele personale (PC) şi până la sistemele de procesare paralelă masivă a datelor, sub medii extrem de diverse, incluzând DOS, Windows, Novell Netware, Macintosh, Unix, OS/2, VMS, OS/400, MVS. Majoritatea liderilor mondiali din industria de programare oferă cel puţin un SGBD, dacă nu mai multe; dintre aceştia, este suficient să amintim IBM, Computer Associates, Sybase Inc., Oracle, Microsoft, Borland. Marile corporaţii ale lumii, ca şi foarte multe dintre cele medii sau mici, depind de peste două decenii de SGBD, cărora le sunt încredinţate funcţiuni critice în afaceri, precum urmărirea vânzărilor, cheltuielilor, stocurilor, încasărilor sau plata salariilor. Dar şi foarte mulţi oameni fac apel la SGBD pentru uzul personal, fie că este vorba de monitorizarea investiţiilor familiale, fie de bd gestionând biblioteca proprie de cărţi, reviste, fotografii, diapozitive, casete audio, video, discuri şi CD-ROM-uri audio, video sau de date etc. Industria de SGBD genera în 1994 venituri depăşind 5 miliarde de dolari anual în lume, cifră mereu în creştere!
Tranzacţii Orice SGBD trebuie să asigure, în primul rând, un limbaj de definire şi manipulare a datelor, conform modelului de date suportat. Prin intermediul acestuia, se oferă utilizatorilor, în esenţă, posibilitatea de a memora datele structurate în bd şi de a le accesa (pentru interogări şi/sau actualizări). Pentru a asigura partajarea datelor în medii multi-utilizator, SGBD trebuie să ofere mecanisme de grupare a tuturor operaţiilor care concură la îndeplinirea unei “sarcini logice unitare” într-o singură tranzacţie, astfel încât SGBD să poată garanta ori că execuţia unei tranzacţii a avut loc complet, fără a fi afectată de alte tranzacţii, ori că tranzacţia nu a fost deloc executată (bd nefiind deci afectată de tranzacţie). Tranzacţiile sunt, prin urmare, singurele “instrucţiuni logice atomice” oferite de un SGBD; ca atare, ele ori se execută integral, ori deloc, în nici un caz parţial, dpdv al oricărei alte tranzacţii. Altfel spus, orice tranzacţie parţial executată (de exemplu, din cauza unei căderi de tensiune) trebuie abortată, iar toate efectele ei trebuie ignorate (“rolled back”). În caz contrar, în mod evident, ar putea rezulta stări inconsistente ale bd. Exemplul 9.1
De exemplu, dacă o tranzacţie măreşte salariile angajaţilor unui departament cu 10%, iar o alta mută angajaţi din acel departament în alte departamente şi cele două tranzacţii nu s-ar executa atomic, ci execuţiile lor s-ar întrepătrunde, unii 5
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 dintre angajaţii mutaţi ar putea avea salariile mărite înainte de mutare iar alţii nu! Pentru păstrarea consistenţei datelor, ori tranzacţia de mărire salarii a fost lansată prima iar cea de mutare angajaţi trebuie lansată după terminarea tuturor măririlor de salarii (cu efectul că toţi angajaţii mutaţi vor avea salariile mărite), ori, invers, tranzacţia de mutare angajaţi a fost lansată prima iar cea de mărire salarii trebuie lansată abia după încheierea tuturor mutărilor (cu efectul că nici unul dintre angajaţii mutaţi nu va avea salariul mărit). Literatura de specialitate se referă, în acest sens, la cele patru proprietăţi ACIDe ale tranzacţiilor: • Atomicitatea execuţiei (ori completă, ori deloc) • Consistenţa (sau Corectitudinea) transformărilor induse conţinutului bd de către tranzacţie • Izolarea execuţiei tranzacţiei, care nu trebuie să fie influenţată de modificările aduse bd de către orice altă tranzacţie concurentă • Durabilitatea tranzacţiei, ale cărei modificări produse bd la terminarea execuţiei sale trebuie să fie permanente, supravieţuind oricăror căderi ale sistemului sau defecţiuni ale suporţilor de stocare a datelor. Conceptul de tranzacţie şi de terminare a ei (“commit”, în engleză) joacă însă un rol la fel de important în controlul concurenţei, impunerea constrângerilor de integritate, salvarea datelor şi recuperarea din erori, aşa cum vom vedea în continuare. Capitolele următoare discută despre problemele de implementare ale principalelor componente şi funcţii ale oricărui SGBD, indiferent de arhitectură sau de modelul suport al datelor, şi anume despre: controlul accesului concurent; securitate; integritate; indexuri; optimizare; cataloage; interfeţe de programarea aplicaţiilor (API); unelte utilitare. De remarcat însă că, pe lângă toate aceste probleme “clasice” ce apar în implementarea SGBD, ca în mai toate domeniile (poate doar cu o viteză mult mai mare) şi această industrie trebuie permanent să se adapteze atât la noile cerinţe ale utilizatorilor, cât şi la avansurile tehnologice hard şi soft. Considerăm că cele mai semnificative tendinţe ce se manifestă azi în industria SGBD sunt următoarele: • • • • •
arhitecturile client / server mediile de calcul deschise, distribuite sistemele multiprocesor, cu procesare paralelă conceptualizarea orientată obiect integrarea în Internet.
Deşi toate acestea depăşesc cadrul fixat pentru prezenta lucrare, considerăm totuşi utilă măcar o trecere sumară în revistă a lor în continuarea acestui capitol introductiv al ultimei părţi.
Arhitecturi Client / Server Până acum aproximativ un deceniu, SGBD erau aproape exclusiv proiectate pentru platforme de calcul centralizat, unicalculator, uniprocesor, care nu erau interconectate între ele. Două clase de SGBD, corespunzând celor două tipuri de platforme de calcul existente până la acea dată, erau disponibile: • off-line (batch, bazate pe job-uri procesate ulterior), rulau pe platforme mari (mainframe, tipic IBM, sub OS, SIRIS sau MVS), folosind cartele perforate, în regim uniutilizator, uniproces; programele nu se executau în timp real, ci erau procesate ulterior, pe baza unui sistem de priorităţi. Acest tip de SGBD primitiv mai este încă folosit şi azi în lume, nu doar din
6
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 considerente de amortizare a investiţiilor uriaşe făcute în echipamente şi programe, sau din conservatorism, ci şi datorită faptului că prelucrarea batch este în continuare cea mai potrivită pentru aplicaţiile de mai lungă durată (tip liste de salarii, de stocuri etc.), intensive, ce nu necesită interacţiune în timp real şi care deci se pretează la execuţia în afara orelor de program ale majorităţii utilizatorilor (exemplu: noaptea), când resursele sistemului de calcul ar fi, altfel, aproape nefolosite. • on-line (asistenţă decizii, procesare tranzacţii în timp real), rulau pe platforme mini (tipic DEC, sub RSX, VMS sau Unix), oferind acces multiutilizator, multiproces, de la mai multe terminale conectate la sistemul de calcul. Acest tip de SGBD este încă majoritar în lume, fiind în continuare folosit de mai toate marile corporaţii, de la bănci la uzine, tendinţa fiind însă de evoluţie spre arhitecturi deschise, client / server. Apariţia PC-urilor, foarte ieftine şi exploziv mai performante an după an, oferind afişaj în culori, o grafică net superioară, icoane, mouse şi lucru în ferestre accesibile nu doar programatorilor de calculatoare, a avut rapid un impact uriaş şi asupra industriei SGBD, ducând în foarte multe companii (mai ales mici şi mijlocii) la desfiinţarea departamentelor informatice, la descentralizarea totală a procesării datelor şi la angrenarea nespecialiştilor în programare în preluarea controlului direct asupra gestiunii datelor. Acestui pionierat în domeniu, întâi sub CP/M, apoi DOS şi Windows, i-au corespuns SGBD-uri de tip dBase. Foarte repede şi nu doar din dorinţa de a utiliza în comun periferice scumpe (discuri hard de mare capacitate, imprimante laser, scanner, CD-ROM etc.) sau de a comunica între PC-uri prin mesaje şi poştă electronică, ci mai ales pentru integrarea bd, eliminarea redundanţelor şi accesul partajat la date, PC-urile au fost interconectate întâi în reţele locale de calculatoare (LAN) şi apoi în reţele regionale (WAN). În special sub Novell Netware, apoi şi sub Windows NT, Windows ’95, SunSoft sau Banyan, piaţa de SGBD corespunzătoare a fost şi este încă dominată de FoxPro, Access şi Paradox. Acestea pot fi configurate atât pentru lucru local, individual, pe un singur PC neconectat în reţea, cât şi pentru lucrul în reţea. Tipic, în acest din urmă caz, unul sau mai multe calculatoare din reţea sunt configurate ca server, iniţial dedicat (de date şi/sau de imprimare) iar celelalte drept, clienţi cuplaţi iniţial, la un moment dat, la un singur server de date şi eventual la unul de imprimare. Ulterior, aceste arhitecturi arborescente iniţiale au fost înlocuite cu arhitecturi mai flexibile (“punct la punct”) în care orice PC poate fi cuplat simultan la orice alt PC, căci fiecare PC poate fi configurat atât server cât şi client. Necesitatea de a factoriza datele comune ale unei companii şi de a asigura accesul rapid la ele, în condiţiile în care volumul şi structura acestora sunt foarte mari, a condus la apariţia de servere SGBD, în general rulând pe un PC foarte puternic sau, mai ales, pe minicalculatoare, la care sunt cuplate clienţi PC într-o arhitectură client / server. La un asemenea server (Oracle, Sybase, DB/2, OpenIngres, MS SQL Server etc.), oferind tipic bd relaţionale accesabile în SQL (“Structured Query Language”, “Limbaj Structurat de Interogare”) sunt cuplabile LAN-uri heterogene din punct de vedere al sistemului de operare în reţea şi SGBD utilizat (de la Paradox 3.5 sub Novell, la Internet Explorer sub Windows’95!). Principalele probleme de implementare relative la arhitecturile client / server sunt legate de: • suport pentru diferite interfeţe de reţea • unelte şi aplicaţii de interfaţă utilizator (“front-end”) pe calculatoarele client pentru cuplarea la server • mecanisme de monitorizare şi optimizare a traficului în reţea.
7
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Sisteme deschise şi bd distribuite Până acum un deceniu, întreprinderile utilizau echipamente de calcul şi programe oferite de un unic furnizor (în majoritate, IBM şi DEC). Între timp, oferta de platforme de calcul, reţele de calculatoare, sisteme de operare şi SGBD s-a diversificat enorm. O mare corporaţie foloseşte azi, de obicei, mai multe SGBD simultan, pe diferite tipuri de calculatoare, aproape toate interconectate, cu mai multe servere SGBD (câte unul per departament sau grup important de departamente şi unul sau mai multe centrale, deservind conducerea superioară a corporaţiei). Aceste realităţi obligă furnizorii de SGBD să asigure portabilitatea lor pe (sau variante dedicate pentru) platforme de calcul multiple, precum şi interoperabilitatea între produsele proprii şi cele similare ale concurenţilor. Asemenea sisteme deschise gestionează în mod natural baze de date distribuite (bdD) şi necesită diverse forme de interfeţe de acces.
Baze de date distribuite Bd distribuite sunt, în multe privinţe, similare arhitecturilor client / server. Ambele abordări implică utilizarea simultană a mai multor sisteme de calcul interconectate, accesul la date aflate la distanţă şi partajarea acestora, precum şi procesarea distribuită. Totuşi există şi diferenţe importante între ele, dintre care două ni se par esenţiale, şi anume: • în bd distribuite sunt interconectate în reţea doar SGBD server (fiecare dintre ele putând sau nu avea conectaţi clienţi proprii); serverele SGBD interconectate cooperează între ele pentru gestiunea în comun a datelor, pentru accesul utilizatorilor locali la acestea, ca şi pentru toate celelalte funcţiuni SGBD abordate în următoarele capitole; • cea de-a doua diferenţă este legată de faptul că arhitecturile distribuite sunt concepute pentru a suporta bd globale, integrate, deşi memorarea datelor şi procesarea lor poate fi răspândită pe o arie geografică largă şi, mai mult, tabelele bd pot fi partiţionate (vertical, pe coloane şi/sau orizontal, pe linii) între servere. Pentru mărirea performanţelor, bd distribuite încearcă mereu să exploateze şi localitatea accesului la ele. Aceasta presupune copierea (replicarea) unor porţiuni ale bd gestionate de orice server distribuit pe alte servere, pentru a micşora traficul în reţea şi a mări disponibilitatea datelor la nivelul local, unde copiile vor putea fi astfel procesate simultan (atât în citire, cât şi în scriere) de mai multe servere. Mai mult, pentru procesarea tranzacţiilor, o bd distribuită poate folosi simultan oricâte dintre serverele de SGBD disponibile pentru a optimiza performanţele execuţiei acestora folosind procesarea paralelă. Dual însă, bd distribuite se bazează şi pe autonomia locală a fiecărui server SGBD component. Aceste sisteme sunt proiectate astfel încât administratorii locali de bd păstrează controlul asupra bd locale corespunzătoare, stabilind inclusiv asupra căror porţiuni de date oferă acces (şi cu ce privilegii) utilizatorilor locali ai altor servere. În plus, nici un server local nu depinde de vreun alt server pentru gestionarea şi accesul la datele proprii, permiţând exploatarea lor chiar dacă vreun alt server nu este temporar în serviciu sau dacă, din cauza unei căderi a reţelei de comunicaţii interservere, vreun nod local rămâne complet izolat de celelalte servere pentru o perioadă de timp. Din punctul de vedere al utilizatorilor însă şi, în special, al programatorilor, cea mai importantă caracteristică a noilor bd distribuite este transparenţa localizării, adică obţinerea independenţei aplicaţiilor faţă de localizarea la un moment dat a datelor. În această abordare a bd distribuite, numită şi “imaginea unui singur sit” (“single-site image”), distribuirea datelor este complet transparentă utilizatorilor; ca atare, de exemplu, se pot muta date de pe un server pe altul fără ca utilizatorii să trebuiască să ştie acest lucru sau să fie în vreun fel afectaţi.
8
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Principalul mecanism prin care este implementată transparenţa localizării este includerea în numele global (“systemwide name”) al oricărui obiect aflat în gestiunea bd distribuite a “locului naşterii” obiectului, deci a locaţiei unde a fost creat iniţial, şi menţinerea informaţiilor despre obiect, pe toată durata existenţei sale, de către SGBD al locului său de naştere. Dacă un obiect este mutat la o altă locaţie, el este “luat în evidenţă” şi de SGBD al noii locaţii (şi “scos din evidenţa” locului de unde s-a mutat, dacă acesta nu este locul său de naştere, întocmai cum procedează Birourile de evidenţa populaţiei sau Comisariatele militare!), dar SGBD de la locul naşterii memorează automat un pointer către noua locaţie a obiectului (sau îl modifică pe cel vechi). În fine, bd distribuite permit natural creşterea incrementală prin adăugarea de noi noduri pe măsură ce cerinţele o impun. De cele mai multe ori, această soluţie este, de departe, mult mai bună decât upgrade-ul vreunui server existent (ce nu ar putea să nu perturbe măcar o vreme utilizatorii locali ai acelui nod).
Programe interfaţă de acces În finalul acestei secţiuni sunt necesare şi câteva cuvinte despre interfeţele (“middleware”) şi porţile (“gateways”) de acces. În general, interfeţele de acces (care au apărut la începutul acestui deceniu) sunt programe care furnizează unor aplicaţii o interfaţă consistentă la nişte servicii suport (ce sunt adesea furnizate de la distanţă, nu local) protejând astfel aplicaţia de diverse alte interfeţe native şi de o mare parte din complexitatea laborioasă impusă cel mai adesea de accesul direct la respectivele servicii suport. De exemplu, o interfaţă de acces ar putea fi responsabilă de rutarea unei cereri locale către unul sau mai multe servere aflate la distanţă, de suportul necesar în interacţiunea cu diverse protocoale de reţea, de eventuala traducere a cererii (de exemplu, dintr-un dialect al SQL în altul), de conversia datelor dintr-un format în altul etc. În particular, în domeniul bd, sunt oferite interfeţe de acces la date; acestea interfaţează utilizatorii la diverse surse de date, precum diferite SGBD relaţionale, non-relaţionale, sau vechi sisteme fişier. Porţile de acces sunt strămoşii interfeţelor de acces; aceste programe, de tip control (“software driver”), asigură conectivitatea (în general limitată) între două sisteme de programe de tipuri precis definite (dar nu neapărat diferite! vezi, de exemplu, Novell Netware). Ele sunt în continuare folosite ori de câte ori nu există (sau ar fi prea scump încă apelul la) interfeţe de acces adecvate.
Medii de procesare paralelă Platformele de calcul multiprocesor se vor impune din ce în ce, inclusiv pe piaţa PC-urilor. Principalele avantaje oferite de ele sunt: • costul mai redus, la aceeaşi putere de calcul oferită, în raport cu calculatoarele cu un singur procesor foarte puternic • potenţialul de scalabilitate inclus (clienţii pot achiziţiona întâi unul sau doar două procesoare, urmând ca restul să poată fi achiziţionate ulterior, pe măsura necesităţilor) • posibilitatea procesării paralele, crucială în mărirea performanţelor oricărui SGBD gestionând volume mari de date complex structurate. Procesarea paralelă este un domeniu extrem de promiţător, deşi momentan nu există prea multe SGBD-uri comerciale capabile de aşa ceva. În special bd logice şi relaţionale ar putea profita din plin de procesarea paralelă, în special în cazul volumelor mari de date, deoarece atât expresiile logice sau de algebră relaţională, cât şi colecţiile de tabele (şi chiar tabelele) pot fi partiţionate “canonic” iar fiecare dintre părţile astfel rezultate pot fi încredinţate câte unui procesor pentru execuţie simultană. În special bd multimedia (pentru care deja doi producători americani de aplicaţii “video la cerere” au adoptat procesarea paralelă!), care presupun gestiunea şi accesul unor date având dimensiuni extrem de mari, dar şi bd uzuale în care concurenţa tranzacţiilor este foarte mare ar avea nevoie stringentă de SGBD bazate pe procesare paralelă.
9
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Există trei tipuri fundamentale de arhitecturi hardware multi-procesor (unele platforme comercializate oferind însă şi combinaţii între aceste arhitecturi), clasificate în funcţie de resursele partajate de procesoare, fiecare dintre acestea cu avantajele şi dezavantajele sale: • nimic partajat; • discuri partajate; • memorie partajată (prin intermediul căreia şi discurile sunt partajate!).
Arhitecturi fără partajare Arhitecturile fără partajare implică memorie, discuri, copii de sisteme de operare şi SGBD distincte pentru fiecare procesor în parte. Ele formează baza sistemelor de procesare paralelă masivă, utilizând deja mii de procesoare ieftine per platformă. Avantajul cel mai mare este că scalabilitatea e aproape liniară (adică performanţele hardware ale sistemului cresc aproape proporţional cu cele ale fiecărui nou procesor instalat). Principalul dezavantaj este însă acela că, software, încărcarea echilibrată a procesoarelor este foarte greu de realizat (mai ales atunci când tranzacţiile accesează des multe date comune, ceea ce are ca efect imposibilitatea unei partiţionări simetrice a datelor şi, deci, supraîncărcarea unui procesor şi nefolosirea celorlalte la puterea lor). În plus, la orice adăugare a unui nou procesor datele trebuie repartiţionate, iar sistemul de operare trebuie să suporte un trafic de mesaje greu pentru unica comunicaţie posibilă, cea interprocesoare. De asemenea, căderea unui procesor sau a memoriei sale au ca efect pierderea posibilităţii de a mai accesa datele de pe discurile acestuia. Ca remediu, unele platforme oferă salvări interdiscuri precum şi procesoare şi memorii redundante, de rezervă. De notat în fine că bd distribuite pot fi considerate, în fond, echivalente unor asemenea arhitecturi multiprocesor fără partajare!
Arhitecturi cu discuri partajate Arhitecturile cu discuri partajate implică doar memorii, copii de sisteme de operare şi SGBD distincte pentru fiecare procesor, dar acces partajat la discuri (în general organizate la rândul lor într-o reţea) printr-un mecanism comun de interconectare a memoriilor la ele. Această arhitectură, ce oferă acces concurent al procesoarelor la aceleaşi date, pune cele mai mari probleme software dintre toate cele trei tipuri fundamentale multi-procesor existente. Deoarece este oricând posibil ca două sau mai multe procesoare să acceseze simultan aceleaşi date de pe disc, pentru a păstra integritatea bd este nevoie de un mecanism global de blocare; acesta este numit gestionarul de blocări distribuit şi e folosit în două scopuri: • pentru punerea şi scoaterea lacătelor (vezi capitolul următor) în funcţie de starea tranzacţiilor executate pe procesoarele concurând la aceleaşi date; şi • pentru gestionarea coerenţei zonelor tampon şi/sau cache asociate procesoarelor concurente (căci e posibil ca un procesor să rescrie data accesată concurent, care nu va mai coincide cu copiile sale din memoria celorlalte procesoare; pentru sincronizarea lor, toate celelalte procesoare trebuie obligate imediat să recitească data respectivă). Principalul avantaj al acestei arhitecturi este că nu e nevoie de nici o partiţionare a bd între procesoare şi deci echilibrarea încărcării acestora este mult mai uşoară. Scalabilitatea nu mai este însă liniară, iar performanţele sistemului se degradează ori de câte ori prea multe procesoare au nevoie de access simultan la aceleaşi date. Unele platforme comerciale însă asigură suport hardware suplimentar pentru gestionarul de blocări distribuit, mărind astfel sensibil performanţele sistemului.
10
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Arhitecturi cu memorie partajată Arhitecturile cu memorie partajată implică o unică memorie, oricâte discuri partajate prin intermediul acesteia şi o singură copie de sistem de operare şi de SGBD, ambele însă de tip “multiexecuţie” (“multithreaded”), singurul tip care poate să suporte şi să exploateze un asemenea mediu multiprocesor. Fiecare procesor poate executa orice sarcină; acestea sunt de altfel preluate pe măsură ce apar, în ordinea priorităţilor ce le sunt asociate, de către primul procesor disponibil. Dezavantajele sunt legate de căderea întregului sistem în cazul oricărei defecţiuni a memoriei şi de competiţia procesoarelor asupra acesteia. Ea nu numai că necesită un mecanism delicat de interconectare a procesoarelor la memorie, dar scade dramatic scalabilitatea: orice nou procesor va interfera cu cele deja existente, “încurcându”-le prin memoria pe care le-o va “fura”. Ca atare, aceste arhitecturi nu pot practic folosi prea multe procesoare; peste un anumit prag, se înregistrează o deteriorare continuă a performanţelor sistemului cu fiecare nou procesor adăugat. Singura soluţie viabilă este cea cu un număr mic de procesoare, toate foarte puternice, ceea ce însă face ca această abordare să fie adesea prea scumpă.
Patru tipuri de cuplare a procesoarelor: strânsă, lejeră, simetrică, şi asimetrică Arhitecturile cu memorie partajată se mai zic şi sisteme strâns cuplate. Iniţial, doar arhitecturile fără partajare erau referite drept sisteme lejer cuplate, dar în ultimii ani acest calificativ a început să fie folosit pentru orice arhitectură în care memoria nu este partajată (incluzând deci şi arhitecturile cu discuri partajate). În sfârşit, sistemele multiprocesor simetrice (SMP) desemnează arhitecturi cu memorie partajată (deci strâns cuplate) particulare, în care fiecare procesor poate fi capabil să proceseze orice cerere (spre deosebire de cele asimetrice, în care unul sau mai multe procesoare sunt dedicate doar cererilor de un anumit tip).
Procesarea paralelă a tranzacţiilor şi interogărilor Procesarea paralelă a tranzacţiilor (zisă şi paralelism interinterogări) presupune execuţia completă a câte unei tranzacţii pe câte un procesor. Mult mai interesantă este însă procesarea paralelă a interogărilor (zisă şi paralelism intrainterogare) în care mai multe procesoare concură simultan la execuţia unei singure interogări dintr-o tranzacţie. Acest tip de paralelism se foloseşte pentru aplicaţii de tip suport decizii care includ interogări complexe, doar în citire însă, implicând join-uri multitabele. Sunt uzuale două tipuri de abordări ale acestui paralelism: • fiecare procesor execută aceeaşi cerere, dar asupra unei alte porţiuni a datelor; • interogarea este subdivizată în subinterogări şi fiecare procesor execută câte una dintre acestea. Prima abordare este, până în acest moment, cea mai răspândită în majoritatea sistemelor paralele comerciale. În esenţă, ea implică o partiţionare prealabilă adecvată a datelor (iar pentru join - şi replicarea celor mai mici tabele dacă discurile nu sunt partajate), procesarea paralelă a interogării şi o reuniune finală a rezultatelor parţiale obţinute de fiecare procesor în parte. Al doilea tip de abordare este abia la început, deoarece necesită un SGBD mult mai puternic, capabil de descompunerea optimizată a interogărilor pentru platforme multiprocesor. În plus, lucrurile se complică foarte mult în cazul arhitecturilor fără partajare, căci este nevoie ori de o optimizare globală, ori de distribuirea optimizării între procesoare, provocare ce încă constituie o problemă deschisă în domeniu.
11
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Procesarea paralelă a indexurilor şi a programelor utilitare Unele SGBD evoluate adaugă alte tipuri de procesări paralele la cele două descrise mai sus; dintre acestea, cele mai importante sunt procesarea paralelă a indexurilor şi cea a programelor utilitare. Ambele oferă o viteză sensibil mai mare în multe cazuri. Astfel, de exemplu, foarte multe tabele au mai mult de o coloană pentru care se menţine un index; cum indexurile trebuie actualizate pentru fiecare actualizare a datelor, un astfel de SGBD va memora diferitele indexuri ai unei tabele pe discuri diferite putând astfel să le actualizeze în paralel, prin folosirea a câte unui procesor per index. Similar, pentru tabele indexate foarte mari, indexurile sunt partiţionate pe mai multe discuri, ceea ce permite chiar citirea lor în paralel (pentru o interogare, de exemplu). Utilitarele pot fi şi ele executate în paralel (între ele sau cu alte tranzacţii); de exemplu, salvările, replicările, încărcarea datelor într-o tabelă vidă, reorganizarea unei bd, recuperarea din eroare, actualizarea cataloagelor de statistici etc. se pretează cel mai adesea la procesări paralele. După o cădere de tensiune, de exemplu, într-o arhitectură fără partajare, fiecare procesor poate efectua în paralel cu celelalte recuperarea proprie din eroare.
Sisteme orientate obiect Schimbările survenite în domeniul inteligenţei artificiale şi limbajelor de programare odată cu introducerea conceptualizărilor orientate obiect încep să aibă impact nu doar asupra SGBD academice; primii paşi pe piaţa SGBD comerciale orientate obiect, chiar dacă încă timizi, au fost deja făcuţi. SGBD orientate obiect (pure) diferă esenţial de cele relaţionale în foarte multe privinţe. Prima dintre ele este desigur segmentul de piaţă vizat: în timp ce SGBD relaţionale au fost concepute, în esenţă, pentru a susţine aplicaţii economico-financiare, SGBD obiectuale sunt mai degrabă proiectate pentru aplicaţii CAD/CAM, CAP, CASE (i.e. aplicaţii asistate de calculator în domeniile proiectării, publicisticii şi ingineriei software). De aici rezultă imediat câteva diferenţe cheie între condiţiile pe care trebuie să le satisfacă cele două tipuri de abordări. Astfel, SGBD relaţionale trebuie să facă faţă următoarelor provocări: • tipurile de date sunt foarte simple, puţine şi mereu aceleaşi (şiruri de caractere, numere, date calendaristice, constante Boolene); tabela este singura structură de date necesară; • tranzacţiile sunt în majoritate scurte (în medie, sub un minut!) iar cele mai lungi sunt doar de ordinul câtorva ore; însă timpul de răspuns este cel mai adesea critic; • interogările sunt extrem de frecvente şi imprevizibile (atât ca expresie, cât şi ca moment al lansării cererii); • concurenţa este foarte mare (ajungându-se până la mii de utilizatori simultani cerând acces la o aceeaşi dată); • sunt necesare foarte multe tipuri de aplicaţii şi unelte de lucru pentru categorii foarte diferite de utilizatori, în majoritate nespecialişti în programare (operatori, personal cu funcţii de conducere la nivel operativ, mediu, directori, asociaţi etc.) dar şi administratori de bd şi programatori specialişti (pentru care este importantă şi cuplarea la cât mai multe limbaje de programare); • robusteţea facilităţilor sistem pentru securitatea accesului la date, recuperarea din eroare, disponibilitatea bd şi optimizarea performanţelor este crucială; • trebuie avute în vedere (şi interconectate) toate platformele de calcul cu putinţă, de la calculatoare portabile până la mainframes. Prin contrast, SGBD obiectuale trebuie să răspundă la alt tip de provocări, şi anume: • sunt necesare tipuri şi structuri de date foarte complexe, imprevizibile (utilizatorii trebuie să-şi poată mereu defini altele noi); • tranzacţiile durează cel puţin câteva ore, media însă fiind de săptămâni! Ele trebuie întrerupte şi reluate cel puţin zilnic; natura lucrului este iterativă, implicând adesea renunţarea la o parte din lucru şi reluarea acestuia într-o altă variantă (fie că este vorba de proiectul pentru o clădire, un cip, o instalaţie industrială, o revistă sau un SGBD!); este necesară memorarea şi
12
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
• • • • •
prelucrarea mai multor versiuni ale obiectelor; deşi foarte important, timpul de răspuns nu este critic; interogările sunt mai rare şi foarte previzibile; concurenţa este mult mai mică (câţiva proiectanţi, maxim zeci); sunt necesare foarte multe unelte de lucru performante dar strict pentru specialişti în timp ce eventualele unelte pentru alte categorii de utilizatori nu prea au mare importanţă; în schimb, este esenţială cuplarea cu un limbaj de programare orientat obiect; facilităţile de securitate, recuperare din eroare, disponibilitate etc. nu sunt atât de importante; în general, platformele de lucru folosite sunt doar staţii de lucru (sau PC foarte performante) interconectate într-un LAN sau cuplate la un SGBD server într-o arhitectură client / server.
În esenţă, se poate spune că SGBD obiectuale (SGBDO) sunt o extensie a limbajelor de programare orientate obiect (LPOO) prin asigurarea persistenţei (memorarea pe disc după terminarea programelor, în locul “uciderii”) obiectelor şi partajabilităţii lor între utilizatori concurenţi. Astfel, SGBDO moştenesc flexibilitatea şi bogăţia semantică a LPOO; preţul ce trebuie plătit este însă dublu: pe de-o parte, specificarea iniţială a structurii bd, ca şi programarea ulterioară a tranzacţiilor (care se face, tipic, în C++ nu în SQL!) sunt mult mai laborioase iar pe de alta, utilizatorii SGBDO trebuie să fie mult mai buni specialişti în programarea calculatoarelor decât cei ai SGBD relaţionale.
Gestiunea obiectelor persistente în arhitecturi client / server Multe dintre SGBDO se bazează pe o arhitectură client / server; pentru a mări performanţele însă se încearcă minimizarea activităţilor server-ului şi maximizarea lucrului local, pe staţiile client. Una dintre cele mai importante probleme de implementarea SGBDO este gestiunea obiectelor persistente pe aceste staţii. Majoritatea SGBDO abordează această problemă cu ajutorul câte unei tabele a obiectelor rezidente (în memorie) per client (TOR); fiecare rând al unei asemenea tabele, ce corespunde câte unui obiect, are două coloane: identificatorul obiectului şi adresa din memorie la care rezidă descriptorul său (acesta, la rândul lui, memorează desigur şi adresa la care rezidă obiectul propriu-zis). Înlănţuirea obiectelor este implementată cu ajutorul pointerilor astfel: descrierea fiecărui obiect conţine un pointer către descriptorul următorului obiect din lanţ; figura 9.1 ilustrează un TOR. Această abordare nu este doar dictată de “swapping” (vezi mai jos), ci şi de considerente de performanţă: în asemenea SGBDO, rezultatul oricărei interogări, de exemplu, este o mulţime de descriptori (şi nu mulţimea obiectelor propriu-zise) nu doar pentru că memoria ocupată de obiecte este, de obicei, mult mai mare decât cea necesară descriptorilor, dar şi pentru că, cel mai adesea, aplicaţiile nu au efectiv nevoie de toate obiectele sau, măcar, nu de toate odată. Atunci când SGBDO primeşte o cerere de acces la un obiect persistent al bd, el consultă TOR (menţinută în memoria RAM) pentru a determina dacă obiectul este deja rezident în memorie sau nu. Pentru mărirea vitezei de căutare în tabelă, aceasta este, de obicei, de tip “hashed” (“talmeş-balmeş”, vezi capitolul 14) pe identificatorul obiectelor. Dacă obiectul căutat nu există în tabelă (este deci prima cerere de acces la el), SGBDO îl cere server-ului, îl converteşte din formatul disc în cel memorie (de obicei aceste formate diferă), îi găseşte loc în RAM unde îl şi încarcă, îi construieşte un descriptor şi adaugă o linie corespunzătoare în TOR. Drept urmare, un asemenea server se zice şi server obiect (căci unitatea de transfer cu clienţii este un obiect). Dacă, la un moment dat, gestionarul memoriei virtuale la dispoziţia SGBDO are nevoie de mai multă memorie RAM decât a mai rămas disponibilă, el alege (conform unei strategii de tip cel mai rar accesat, cel care nu a mai fost accesat de cel mai mult timp sau “în cerc” (“round-robin”) etc.) unul sau mai multe obiecte rezidente pe care le mută într-un fişier temporar disc (“swapping”) eliberând astfel memoria necesară. Descriptorii obiectelor astfel evacuate temporar din RAM rămân în memorie, dar pointerul lor către obiectul propriu-zis corespunzător este anulat (devine nil). Ulterior, la o nouă cerere de acces la un asemenea obiect, SGBDO îl va reîncărca în RAM din fişierul disc temporar, fără nici un acces la server.
13
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Un alt tip de implementare, mai nou, este cel folosit de serverele pagină. La acestea, formatul de memorare al obiectelor este acelaşi pe disc şi în memoria RAM; transferul între server şi clienţi se face nu la nivel de obiect ci de pagină (care, de obicei, conţine mult mai multe obiecte); nu mai există TOR, ci doar o zonă a memoriei virtuale a fiecărui client în care sunt memorate pagini de obiecte; în cazul în care se încearcă accesul la un obiect inexistent în această memorie, SGBDO procesează o “capcană de pagină” ce are ca efect aducerea de pe server a paginii ce conţine obiectul respectiv; nu se mai folosesc descriptori de obiecte, toţi pointerii indicând obiectele direct; ca atare, atunci când obiectele sunt mutate în altă zonă a memoriei virtuale (de exemplu, ca efect al swapping-ului), pointerii spre ele trebuie actualizaţi corespunzător. Desigur că, pentru anumite bd (în care o pagină conţine mai multe obiecte) această abordare este mai performantă, atât datorită minimizării transferurilor client / server, cât şi prin eliminarea indirectării referinţelor la obiecte prin descriptori.
Cerere de acces la obiectul O Tabela Obiectelor Rezidente (TOR) ID_X ...
Descriptor_X
Obiectul X
Descriptor_O ID_O ...
ID_Y ...
Obiectul O
Descriptor_Y
Obiectul Y
Figura 9.1 Un exemplu de memorare a obiectelor persistente înlănţuite
Un exemplu de bd orientată obiect Exemplificăm abordarea orientată obiect a bd cu ajutorul SGBDO ObjectStore (al firmei Object Design, Inc.) ce se bazează pe C++. Cu ajutorul bibliotecii C++ Library Interface furnizate de acest SGBDO, vom crea o clasă simplă numită “colecţie” şi vom scrie apoi un program care crează instanţe persistente ale acestei clase. Instrucţiunile suplimentare ale SGBDO care nu există în C++ vor fi scrise îngroşat în acest exemplu numai pentru a le scoate în evidenţă. Orice element dintr-o colecţie (o mulţime ce admite duplicate!) este caracterizat simplu, doar de un identificator id_ob şi un nume, plus un pointer urm_ob către următorul obiect al colecţiei. Funcţiile membre ale acestei clase sunt şi ele reduse la minim: un constructor (pentru crearea de noi obiecte membre ale colecţiei); un destructor (pentru eliminarea unui obiect din colecţie); şi un vizualizator (pe ecran, al datelor despre un obiect). Declaraţia colecţie astfel definită este prezentată în figura 9.2. De remarcat în corpul constructorului că, după asignarea primului şi ultimului parametru (componentelor id_ob şi, respectiv, urm_ob), este întâi nevoie de a calcula lungimea celui de-al doilea parametru (numele obiectului) şi de a aloca spaţiul corespunzător pentru el, instruind ObjectStore să memoreze
14
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 această informaţie în acelaşi segment al bd cu restul obiectului (lucru realizat de o formă supraîncărcată a operatorului C++ “new”) înainte de a copia al doilea parametru în nume. Figura 9.3 prezintă un program simplu ce creează obiecte persistente înlănţuite ale colecţiei astfel definite şi le afişează. SGBDO ObjectStore deschide o bd anume (“/u/guest/testdb”, convenţia de numire folosită conformându-se standardului Unix); după ce se obţine de la utilizator numărul dorit de obiecte, SGBDO lansează o tranzacţie de actualizare date (“update”) şi se verifică dacă există deja creată o rădăcină (punct de intrare) pentru lista înlănţuită a obiectelor colecţiei; în caz contrar, se creează o asemenea rădăcină. După crearea şi listarea instanţelor create, sunt închise tranzacţia de actualizare şi bd.
Integrarea în Internet Cea mai fascinantă pagină din câte se scriu probabil în această perioadă în domeniul ştiinţei calculatoarelor este probabil cea referitoare la spaţiul cibernetic asociat Internet-ului. Chiar dacă acest subiect depăşeşte cu mult cadrul prezentei lucrări, am dori să menţionăm totuşi cele trei provocări majore pe care considerăm că Internet le adresează SGBD: • SGBD multimedia, pentru gestiunea nu doar a datelor numerice, text şi Boolene, ci şi a celor audio-video; • SGBD gestionând meta-date, despre ierarhiile laticeale de date disponibile în Internet (structurare, căi de acces, eventual rezumate); • mecanisme de fluidizare a traficului în reţea şi de garantare a accesului şi optimizare a costului acestuia, în orice moment, la orice resursă de date, de la orice post de lucru conectat. Desigur că fiecare dintre acestea în parte au fost deja abordate de industria SGBD, dar nu încă sistematic şi masiv în contextul Internet, care, prin complexitatea, vastitatea, lipsa de omogenitate şi viteza explozivă de dezvoltare (Japonia a început comercializarea pe piaţa sa a televizoarelor Sanyo, Mitsubishi şi Sharp direct conectabile la Internet!) modifică de cele mai multe ori în chip radical datele problemelor de proiectare şi implementare aferente. Astfel, de exemplu, în SUA sunt deja operaţionale de câţiva ani SGBD multimedia de tip “filme la cerere” (“video-on-demand”) prin care companii de televiziune prin cablu oferă abonaţilor nu doar filme preprogramate de compania respectivă, ci le permit acestora să-şi aleagă dintr-o bd de filme ce programe doresc fiecare să vizioneze şi la ce oră anume! Despre meta-date vom vorbi mai în amănunt, dar doar în contextul SGBD, în capitolul 16. La fel, despre fluidizarea traficului în reţele de calculatoare, despre garantarea accesului la date şi optimizarea acestuia în condiţii de concurenţă vom discuta în următoarele capitole, dar, iarăşi, din păcate, nu şi în contextul Internet-ului. Încă o dovadă (dacă mai era nevoie!) că viteza de evoluţie în domeniul acesta este extraordinară o constituie lansarea recentă pe piaţă (după redactarea lucrării, dar înainte de susţinerea ei!) de către Microsoft a pachetului Office97, proiectat şi realizat folosind tehnologiile Internet (format HTML, hiperlegături, navigare Web etc.) pentru cuplarea oricărui PC la Internet, din orice componentă a sa, inclusiv din SGBD Access’97. Principala caracteristică remarcabilă a acestei noi versiuni este aceea că utilizatorii PC pot crea pagini Web conţinând imagini active ale datelor, astfel încât navigatoarele Web pot actualiza, şterge sau adăuga informaţii. În plus, datele pot fi sincronizate prin replicare între calculatoarele conectate, astfel încât ultima lor versiune să fie tuturor accesibilă rapid. Într-un viitor extrem de apropiat, întreaga planetă va fi acoperită de o unică bd distribuită, plină cu PC-uri nu doar client ci şi server de date! Mai mult, tehnologia Internet este, prin Office97, disponibilă şi în LAN (referite acum ca Intranet) faţă de care nu mai există, practic, nici o diferenţă!
15
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 // Fişier antet pentru clasa colecţie // antete fişier I/O C++ şi ObjectStore #include #include < ostore/ostore.hh> class colecţie public: // date membru publice int id_ob; // identificator obiect char *nume; // pointer către numele obiect colecţie *urm_ob; // pointer către următorul obiect al colecţiei // funcţii (metode) membru publice colecţie(const int, char*, colecţie*); // constructorul de obiecte ~colecţie(); // destructorul de obiecte void afişează(); // vizualizatorul obiectelor instanţiate ; // corpul funcţiilor membru publice // creare specificaţii de tip pentru ObjectStore (obligatorii pentru toate // tipurile/clasele pentru care se cere instanţierea de obiecte persistente) extern os_typespec char_type; // constructorul de noi instanţe ale colecţiei colecţie::colecţie(const int num, char *nume, colecţie *next) id_ob = num; urm_ob = next; // alocă spaţiu pentru nume şi copiază-l int lung = strlen(nume)+1; this→nume = new(os_segment::of(this), lung, &char_type) char[lung]; strcpy(this→nume, nume); // destructorul dual colecţie::~colecţie() // şterge spaţiul alocat obiectului nume delete nume; // afişează pe ecran informaţiile despre un obiect void colecţie::afişează() cout << “ID obiect: “<< id_ob << ‘\t’ << “Nume: ” << nume << endl; Figura 9.2 Declaraţia unei clase colecţie în SGBDO ObjectStore (“colecţie.hh”)
16
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 // Exemplu de program pentru crearea şi afişarea unei colecţii înlănţuite de obiecte. // ObjectStore este folosit pentru asigurarea persistenţei obiectelor create. #include “colecţie.hh” os_typespec char_type(“char”); main()
// declaraţia clasei colecţie
// iniţializare variabile colecţie *head = 0; // capul listei înlănţuite de obiecte int număr = 0; // numărul de ID obiect char nume_ob[32]; // vector pentru numele obiect int total = 0; // numărul total de obiecte os_database *db1 = 0; // pointer la o bd ObjectStore os_database_root *root = 0; // pointer la o rădăcină ObjectStore os_typespec col_type(“colecţie”) objectstore::initialize(); db1 = os_database::open(“/u/guest/testdb”, 0, 0666); // cere numărul de obiecte dorite cout << “Specificaţi numărul de instanţe dorite pentru colecţie: “<< endl; cin >> total; OS_BEGIN_TXN(t1, 0, os_transaction::update) root = db1→find_root(“col_root”); if (!root) root = db1→create_root(“col_root”); head = (colecţie*)root→get_value(); // crează obiectele for (int i = 0; i < total; i++) cout << “Specificaţi ID următorului obiect dorit: “<< endl; cin >> număr; cout << “Specificaţi numele următorului obiect dorit: “<< endl; cin >> nume_ob; head = new(db1, 1, &col_type) colecţie(număr, nume_ob, head); root→set_value(head); // afişează toate obiectele colecţiei cout << “Lista tuturor obiectelor colecţiei create: “<< endl; for (colecţie* e = head; e; e = e→urm_ob) e→afişează(); OS_END_TXN(t1) db1→close();
Figura 9.3 Program ObjectStore pentru crearea şi afişarea de obiecte persistente
17
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Cinci exemple de SGBD celebre Ambiţia acestei părţi a lucrării de a schiţa, pe lângă componentele şi funcţiile clasice ale oricărui SGBD, şi tendinţele actuale în această industrie a avut şi efectul limitării investigaţiilor noastre la doar câteva SGBD comerciale evoluate pentru ilustrarea teoriilor în domeniu. Ne-am oprit astfel, în esenţă, la 5 asemenea sisteme, de altfel printre cele mai cunoscute, vândute şi utilizate în lume în acest moment şi anume: DB2 (al IBM), Oracle (al Oracle), SQL Server (al Sybase), NonStop SQL (al Tandem) şi CA-OpenIngres (acum al Computer Associates). În această secţiune prezentăm doar câte o vedere de ansamblu asupra lor; ultima secţiune (de comentarii şi referinţe bibliografice) a fiecărui capitol din această ultimă parte este în principal dedicată modului în care sunt implementate considerentele teoretice dezvoltate anterior în aceste SGBD celebre. Pe lângă acestea, sporadic, apar şi referiri la Microsoft SQL Server [262], Microsoft Access’95 [154,259], Microsoft Visual FoxPro [261] şi Borland Paradox [74,255].
DATABASE2 (DB2) MVS / ESA versiunile 3 şi 4 ale IBM Cel mai răspândit şi celebru SGBD din lume rămâne deocamdată DATABASE2 (DB2) al IBM, lansat în 1983. Din această familie de produse (pentru diverse platforme de calcul) am ales pentru analiza noastră versiunea de vârf, pentru calculatoare mari (mainframes) proiectată a rula sub sistemul de operare MVS / ESA (în afară de această versiune completă a produsului, familia mai cuprinde încă 6 membri: DB2/2, pentru OS/2; DB2/6000, pentru AIX; DB2 pentru VM şi VSE, adică fostul SQL/DS; DB2/400, pentru OS/400; DB2/HP/UX, pentru Unix-ul HP; şi DB2 pentru Sun Solaris). E.F. Codd, părintele modelului relaţional al datelor (perioadă în care era cercetător al IBM!), este şi părintele DB2, chiar dacă indirect, prin prototipul System R. DB2 este un SGBD complet, încorporând toate funcţiunile cunoscute în domeniu, înclusiv distribuirea datelor şi procesarea paralelă. Informaţiile furnizate în această a treia parte se referă la versiunea 3, curentă în acest moment, dar sunt incluse şi principalele îmbunătăţiri anunţate pentru versiunea 4 ce abia a fost lansată comercial. Trebuie notat şi faptul, deloc neglijabil, că DB2 este oferit de IBM împreună cu familii întregi de utilitare şi de alte produse IBM cu care DB2 cooperează: compilatoare şi interpretoare pentru aproape o duzină de limbaje de programare (vezi capitolul 17), aplicaţii de tip suport decizii (gestionarul interogărilor, vizualizatorul datelor etc.), instrumente de asistenţă a dezvoltării aplicaţiilor (VisualGen, VisualAge), unelte pentru administratorii de sistem (DataHub, DB2PM, Estimator, DFSMS, RACF etc.) etc. În plus, o întreagă industrie complementară gravitează în jurul DB2 (al IBM în general!) oferind diverse alte produse ale altor firme, atât completând (sau chiar concurând) cele ale IBM, cât şi oferind alte tipuri de aplicaţii, unelte şi conectivitate.
Oracle 7.1 al Oracle Principalul concurent tradiţional al IBM rămâne Oracle, prima companie care a oferit pieţei un SGBD comercial (în 1979, pentru VAX/VMS). Fondată în 1977 în California, micuţa firmă de atunci a evoluat rapid ajungând unul din cei mai mari producători mondiali de software, ale cărui sisteme au fost realizate pentru şi rulează încă pe mai mult de 80 de tipuri de platforme de calcul diferite. DEC, Sun şi Sequent sunt cei mai mari producători de echipamente cu care Oracle are semnate contracte de colaborare permanente. Şi SGBD Oracle este bazat pe cercetările Dr. E.F. Codd şi ale colegilor săi de la IBM, fiind centrat în jurul SQL. Analiza noastră are în vedere versiunea curentă, 7.1, a serverului Oracle; acesta poate fi achiziţionat singur sau împreună cu opţiunile pentru bd distribuite (Distributed Option) şi/sau pentru medii de procesare paralelă (Parallel Server Option şi Parallel Query Option). Şi SGBD Oracle este furnizat în centrul a numeroase familii de produse complementare ale firmei Oracle şi ale altor furnizori
18
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 de software. Mai interesant în această privinţă este însă “Cooperative Development Environment” (CDE) ce reprezintă încercarea Oracle de a furniza o mulţime de oferte integrate care să acopere întreg ciclul de viaţă al dezvoltării aplicaţiilor.
SQL Server 10.0 al Sybase Dacă Oracle rămâne principalul competitor al IBM în Europa, poziţia sa de secund pe piaţa S.U.A. a fost luată în ultimii ani de SGBD SQL Server al companiei americane Sybase. Fondată în 1984, ea a oferit pieţei abia în 1987 prima versiune a acestui SGBD relaţional pentru arhitecturi client / server şi cu extensii orientate obiect, care poate rula pe diverse versiuni de Unix, OS/2, VMS, Netware ş.a. Principala opţiune curentă în afară de Secure Server (vezi capitolul 12) este Navigation Server, o extensie exploatând procesarea paralelă pe platforme NCR 3600. Pe lângă acestea, sunt livrabile diferite alte pachete de aplicaţii şi utilitare. Versiunea curentă a sistemului este 10.0. SQL Server al Sybase a fost folosit, prin contract, până în 1994 şi de Microsoft (întâi doar sub OS/2, apoi şi pentru Windows NT). De atunci, între cele două companii a intervenit competiţia, Microsoft achiziţionând patentul versiunii 4.2 şi începând modificările şi dezvoltarea unui Microsoft SQL Server propriu.
NonStop SQL / MP al Tandem Fondată în 1974, Tandem a oferit la început doar platforme hardware cu componente redundante şi software asociat pentru asigurarea unei înalte toleranţe la erori. Pe parcurs, firma s-a specializat în arhitecturi pentru procesări paralele masive, multi-procesor (minim 2, maxim 16 procesoare) cuplate lejer, fiind celebre familiile Integrity şi Himalaya; ultima dintre acestea este proiectată în plus pentru sisteme distribuite, permiţând cuplarea de 256 astfel de servere (fiecare având maxim 16 procesoare) într-un singur LAN sau WAN. Platformele Himalaya beneficiază de un sistem de operare propriu, NonStop Kernel, care suportă propriul SGBD lansat în 1987 (şi ajuns acum la a treia generaţie) NonStop SQL / MP. Celelalte platforme Tandem sunt proiectate, în general, pentru Unix, compania având contracte de colaborare şi vânzări pentru ele cu mulţi producători celebri de software, dintre care se detaşează Oracle, Informix şi Sybase. NonStop SQL este unul dintre cele mai moderne şi performante SGBD relaţionale de pe piaţă, proiectat şi construit pentru medii distribuite formate din noduri de calcul cu procesare paralelă. El include o interfaţă conversaţională pentru SQL (SQLCI) şi suport pentru C, Pascal şi COBOL. Firma mai oferă utilitare pentru administrarea sistemului, precum şi facilităţi reţea, inclusiv “gateways” către Oracle, Sybase şi Windows. Mulţi alţi furnizori de software oferă produse suplimentare pentru NonStop SQL.
CA-OpenIngres al Computer Associates Al doilea SGBD relaţional important în ordinea lansării pe piaţă a fost Ingres, comercializat începând cu 1981 de firma Relational Technology Inc., fondată de înşişi autorii proiectului Ingres, cercetători la Berkeley sub conducerea lui Michael Stonebraker. Bazat tot pe teoria genialului E.F. Codd, Ingres nu a folosit însă abordarea algebrică relaţională (ce fundamentează SQL), ci calculul relaţional predicativ al tuplilor; acesta a fundamentat limbajul QUEL, dezvoltat de Stonebraker şi compania, în jurul căruia gravitează încă Ingres (deşi, între timp, sistemul oferă şi SQL). Redenumită ulterior Ingres, Relational Technology este achiziţionată în 1990 de grupul ASK (specializat în software pentru industria constructoare de maşini). Din 1994, “ASK Ingres” a fost cumpărată de puternicul concern Computer Associates. Acum numit CA-OpenIngres, acest SGBD rulează pe mai mult de 35 de tipuri de platforme hardware, în marea majoritate însă sub Unix şi VMS. El include facilităţi client / server şi de bd distribuite
19
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 (prin interfaţa Ingres / Net), plus The Knowledge Manager, care asigură mecanisme de controlul integrităţii datelor şi utilizării resurselor. Opţiunea Object Manager, orientată obiect, oferă posibilitatea definirii de tipuri de date şi metode utilizator. Informaţiile din această ultimă parte se referă la versiunile curente ale tuturor acestor componente şi în special la versiunea R6.4 a motorului Ingres / Star al SGBD.
Comentarii şi referinţe bibliografice Literatura de specialitate abundă în monografii dedicate atât aspectelor teoretice, cât şi celor de implementare ale SGBD. Dintre acestea menţionăm lucrările de referinţă pe care le datorăm celebrilor Ullman [336,337], Date [122,123] sau Papadimitriou [276], dar şi monografii mai noi, precum cele de Gray şi Reuter [166], Bontempo şi Saracco [73] sau ElMasri şi Navathe [133]. Dintre articolele specializate privitoare la arhitecturi client / server, recomandăm pe cele din 1994 ale lui David Linthicum [227,228]. Din multitudinea de texte privitoare la sisteme deschise şi bd distribuite, semnalăm excelentele contribuţii ale lui Bernstein [65] şi ale IBM Corp. [179,180]. Pentru mediile de procesare paralelă, Hsiao [174] şi, din nou, o echipa IBM [265] reprezintă certe autorităţi în domeniu. SGBD orientate obiect sunt analizate în profunzime de câteva texte de referinţă, dintre care se disting contribuţiile lui Kemper şi Moerkotte [196], Stonebraker [325] şi Jacobson and al. [186]. Extinderea modelului relaţional şi abordările hibride iniţiale (exemplu: proceduri memorate, trăgaciuri, câmpuri foarte lungi sau BLOBs, tipuri de date şi funcţii definite de utilizator) propuse de POSTGRES [326] sau Starburst [233] au fundamentat SGBDO comerciale Illustra [325], respectiv DB/2 (chiar dacă acesta din urmă încorporează doar câteva din caracteristicile Starburst). O abordare diferită oferă OpenODB [15] dezvoltat de Hewlett-Packard, care suprapune un strat de gestiune a obiectelor peste un SGBD pur relaţional. Stratul orientat obiect suportă un mănunchi de limbaje de programare extrem de heterogen, alcătuit din aproape toate limbajele ce încă subzistă pe piaţă (Fortran, COBOL, alături de Pascal, C şi C++) şi foloseşte o interfaţă SQL orientată obiect. Dintre conceptele orientate obiect, OpenODB oferă tipurile de date utilizator, ierarhii de clase, moştenire multiplă şi supraîncărcare. Cadrul restrâns al acestei lucrări nu permite tratarea în mai mare detaliu a abordărilor orientate obiect existente în acest domeniu în care, deocamdată, lipseşte vreun model unitar sau vreo standardizare. Totuşi, în 1993, un număr de companii importante în domeniu (incluzând Object Design, Ontos, OS2 Technology, Objectivity şi Versant) au format “Object Database Management Group” cu scopul de a schiţa un standard pentru un model obiectual al datelor şi un limbaj de programare pentru SGBD orientate obiect [29]. Acestea includ limbaje de definire şi manipulare a obiectelor, un limbaj nonprocedural de interogare obiectual (parţial bazat pe SQL) şi punţi de legătură către Smaltalk şi C++. SGBD ObjectStore cu care am exemplificat abordarea orientată obiect în subsecţiunea 9.6.2 este descris în [220]. Despre Internet “curge” probabil deja în lume un fluviu de cărţi şi articole! Dintre ele, recomandăm măcar [188]. Pentru informaţiile referitoare la cele 5 SGBD celebre analizate în partea a treia a lucrării, am apelat la următoarele surse bibliografice: • pentru DB2, [104, 116, 122, 167, 180] • pentru Oracle, [273] • pentru SQL Server al Sybase, [327] • pentru NonStop SQL al Tandem, [328] • pentru CA-OpenIngres, [323]
20
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
2. CONTROLUL CONCURENŢEI Lacăte Gestiunea accesului concurent la bd de către mai mulţi utilizatori simultan trebuie să garanteze consistenţa şi integritatea datelor. Cel mai simplu mod de a le asigura este, evident, serializarea tranzacţiilor, adică punerea într-o coadă de aşteptare a tuturor tranzacţiilor şi execuţia lor pe rând, una câte una (într-o ordine oarecare, bazată, de exemplu, pe priorităţi şi ordinea cronologică de lansare), pe măsură ce execuţia tranzacţiiilor precedente se încheie. Această strategie de implementare a controlului concurenţei nu poate fi însă aplicată de nici un SGBD din cauza performanţelor complet neacceptabile ce ar fi astfel oferite. Pentru a rezolva problema concurenţei, SGBD controlează traficul tranzacţiilor folosind un mecanism de sincronizare software numit lacăt. Un lacăt este asociat unei date (structurate, de obicei rând de tabelă sau tabelă întreagă) pentru a-i indica starea curentă şi a asista astfel sistemul în a decide dacă acea dată este sau nu disponibilă la un moment dat pentru un anumit tip de operaţie (exemplu: modificare). Folosind lacătele, SGBD încearcă mereu să asigure performanţe cât mai mari ale sistemului, fără a se altera datele bd (i.e. fără a se pierde actualizări, de exemplu permiţând unei tranzacţii să rescrie sau să invalideze modificările efectuate de o altă tranzacţie). Exemplul 10.1 De exemplu, să considerăm o firmă cu doi asociaţi şi un singur cont în bancă. Într-o zi, în care, de exemplu, soldul contului este de 1.000.000 lei, simultan, ambii asociaţi se duc fiecare la câte o altă sucursală a băncii care le gestionează contul, primul dorind să facă o plată prin bancă de 500.000 lei, iar al doilea dorind să retragă din cont 300.000 lei. Deşi este evident că, dacă cele două tranzacţii sunt corect serializate, la sfârşitul lor soldul contului ar trebui să fie de 200.000 lei, în absenţa unui mecanism de control al concurenţei de tipul lacătelor soldul final ar putea fi incorect, de exemplu, în următoarea situaţie: 1. Funcţionarul primei sucursale citeşte din bd soldul de 1.000.000 al contului. 2. Funcţionarul celei de-a doua sucursale citeşte din bd soldul de 1.000.000 al contului. 3. Funcţionarul primei sucursale operează plata de 500.000 şi scrie soldul final de 500.000 (1.000.000 - 500.000). 4. Funcţionarul celei de-a doua sucursale operează retragerea de 300.000 şi scrie soldul final de 700.000 (1.000.000 - 300.000). În acest mod, rezultatul primei tranzacţii s-a pierdut, căci cea de-a doua a rescris-o! În majoritatea SGBD moderne, lacătele sunt puse şi scoase automat de sistem, fiind deci transparente utilizatorilor. Deoarece acest lucru încă ar putea conduce, în anumite situaţii, la ineficienţa sistemului, se permite şi programatorilor să controleze lacătele prin instrucţiuni dedicate de punere şi scoatere a acestora. Pentru atingerea unui compromis cât mai acceptabil între controlul automat şi cel manual, sunt practic utilizate mai multe tipuri de lacăte iar datele sunt blocate cu lacăte pe mai multe niveluri, aşa cum se va vedea în subsecţiunile următoare.
Cele două tipuri fundamentale de lacăte: partajabil şi exclusiv Principalele două tipuri de lacăte oferite de aproape orice SGBD sunt partajabil şi exclusiv. Lacătele partajabile sunt asociate cu operaţiile de citire; datele blocate cu un asemenea lacăt pot fi citite simultan de oricâte tranzacţii concurente. Lacătele exclusive sunt asociate operaţiilor de scriere; doar o singură tranzacţie (cea care a reuşit să le blocheze exclusiv) are acces la aceste date, toate celelalte tranzacţii concurente neavând nici măcar dreptul de citire. Lacătele exclusive sunt deci incompatibile cu
21
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 orice alte lacăte, în sensul că o tranzacţie nu poate pune un asemenea lacăt pe nişte date, decât după scoaterea tuturor altor lacăte de pe acele date. Lacătele partajabile sunt compatibile între ele, adică orice tranzacţie poate pune un asemenea lacăt pe nişte date care mai sunt deja blocate de alte tranzacţii, tot cu lacăte partajabile. Figura 9.1 prezintă un exemplu de control al concurenţei mai multor tranzacţii folosind lacăte partajabile şi exclusive. Diverse SGBD comerciale oferă şi alte tipuri de lacăte în afara acestora două fundamentale deja discutate; câteva dintre ele vor fi trecute în revistă în ultima secţiune, de comentarii, a acestui capitol.
Granularitatea Pe lângă diversele tipuri de lacăte oferite, SGBD asigură şi diferite niveluri de control al blocării datelor. Acestea determină granularitatea lacătelor suportate de sistem, care poate varia de la o întreagă bd, la un fişier sau un articol dintr-un fişier. Diverse tipuri de lacăte pot fi folosite pe diverse niveluri de granularitate. Momente de timp
EVENIMENTE UTILIZATOREVENIMENTE SGBD
t1
Începe tranzacţia 1. Cerere de citire data A.
t2
Tranzacţia 1 citeşte A. Începe tranzacţia 2. Cerere de citire data A.
t3
Tranzacţia 2 citeşte A. Începe tranzacţia 3. Cerere de modificare A.
t4
Se termină tranzacţia 1.
t5
Începe tranzacţia 4.
t6
Se termină tranzacţia 2.
t7
Se termină tranzacţia 4.
t8
Tranzacţia 3 modifică A. Se termină tranzacţia 3.
Verifică starea de blocare a lui A. Cum nici un lacăt nu e pus, se garantează un lacăt partajabil pentru tranzacţia 1. Verifică starea de blocare a lui A. A fiind blocat partajabil, se garantează un lacăt partajabil şi pentru tranzacţia 2. Verifică starea de blocare a lui A. A fiind deja blocat (chiar dacă doar partajabil!) se refuză blocarea exclusivă a lui A pentru tranzacţia 3, care va trebui să aştepte deblocarea A pentru a putea continua. Lacătul partajabil pus asupra lui A de ea este scos (rămâne însă celălalt lacăt!). Verifică starea de blocare A. A fiind blocat partajabil, se garantează un lacăt partajabil şi pentru tranzacţia 4. Lacătul corespunzător este scos (dar A este încă blocată de tranzacţia 4!). Lacătul corespunzător este scos şi cum A nu mai este blocat de nici o altă tranzacţie se garantează un lacăt exclusiv pentru tranzacţia 3. Se scoate lacătul exclusiv corespunzător, data A redevenind liberă.
Figura 10.1 Un posibil scenariu de utilizare a lacătelor partajabile şi exclusive
22
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Raţiunea de a introduce mai multe niveluri de granularitate este evidentă: unele tranzacţii (precum cele din exemplul 9.1 de mai sus) pot avea nevoie de acces (ACID!) la mai multe date odată, în timp ce altele (precum cele din exemplul 10.1 de mai sus) au nevoie de acces (ACID!) la o singură dată. Desigur că, pentru a maximiza performanţele sistemului, este important ca nivelurile de granularitate să fie bine alese şi judicios folosite, astfel încât să nu se blocheze inutil date şi să nu fie excesiv de multe blocări/deblocări (care adaugă timp sistem). Majoritatea SGBD-urilor oferă cel puţin trei niveluri de granularitate: articol fişier (rând din tabelă); pagină; fişier (tabelă). Paginile de date sunt unităţi de alocare a memoriei pe disc, a căror dimensiune, multiplu de 2Koct., variază în funcţie de sistemul de operare şi de SGBD (tipic, între 2K şi 64K). În general, o pagină conţine un număr întreg de articole, iar un fişier se întinde pe mai multe pagini. În unele SGBD, o pagină poate conţine articole din mai multe fişiere (cu date structural legate între ele). Deşi paginile de date nu sunt conceptualizate de modelele de date suport ale SGBD, totuşi acest nivel de granularitate are sens, aşa cum rezultă din următorul exemplu: Exemplul 10.2
Să presupunem că o tranzacţie include o interogare ce se referă doar la articolele dintr-o pagină de date. Evident că blocarea acestei pagini doar cu un lacăt este preferabilă atât blocării (inutile a) întregului fişier, cât şi blocării cu câte un lacăt individual a tuturor articolelor paginii (soluţie ce ar mări foarte mult încărcarea sistemului). Unele SGBD evoluate oferă în plus un mecanism automat de “escalare a lacătelor” (sau “blocare progresivă”) pentru mărirea performanţelor sistemului: atunci când un lacăt cu granularitate prea fină este repetat pus (încărcând excesiv sistemul) SGBD poate decide (dincolo de un prag setabil) că ar fi mai economic să mărească granularitatea, înlocuind lacătul cu unul mai larg (de exemplu, de la articol la pagină sau chiar la fişier). Această mărire progresivă a granularităţii este făcută automat, fiind transparentă tranzacţiei implicate.
Niveluri de izolare a lacătelor Unele SGBD oferă, de asemenea, diverse niveluri de izolare a lacătelor (sau durată a lacătelor) ce controlează momentul în care se scot lacătele. Pentru lacătele de citire (exemplu: partajabile) sunt comune cel puţin două asemenea niveluri: citiri repetabile şi stabilitatea cursorului.
Izolarea citirilor repetabile Izolarea citirilor repetabile forţează SGBD să menţină lacătul (partajabil) până la sfârşitul tranzacţiei, asigurând acesteia nemodificarea datelor astfel blocate pe tot parcursul execuţiei tranzacţiei (care va reciti deci mereu aceeaşi valoare a datelor respective). Desigur că asemenea izolări inhibă execuţia concurentă a tuturor tranzacţiilor ce ar trebui să modifice datele respective; pentru a nu afecta performanţele sistemului, toate tranzacţiile care necesită o asemenea izolare ar trebui să se termine cât mai rapid cu putinţă.
Stabilitatea cursorului Stabilitatea cursorului impune SGBD să blocheze datele doar atâta timp cât ele sunt cele curente. Atunci când cursorul (care indică articolul curent al fişierului din care se citeşte) este mutat pe alte date decât cele curent blocate, sistemul scoate automat lacătul (partajabil) asociat datelor ce nu mai sunt indicate de cursor. Evident că această izolare a lacătelor de citire este duală primeia, mărind
23
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 concurenţa; există însă tranzacţii pentru care ea este inaplicabilă deoarece, desigur, o recitire ulterioară a aceloraşi date poate furniza valori diferite de citirea anterioară (căci, între timp, alte tranzacţii au putut modifica datele respective).
Blocarea în două faze Idealul urmărit de orice mecanism de control al concurenţei este, evident, garantarea serializabilităţii, adică atingerea unui aceluiaşi conţinut al bd cu cel care s-ar obţine printr-o serializare a tranzacţiilor (i.e. execuţia tranzacţiilor una după alta, fără nici o concurenţă). Protocolul de blocare în două faze garantează serializabilitatea; varianta sa iniţială preciza doar că, într-o primă fază, tranzacţiile trebuie să obţină blocarea tuturor datelor de care au nevoie; în cea de-a doua, ele nu mai au voie să ceară nici o nouă blocare, ci dimpotrivă, pe măsură ce nu mai au nevoie de acces la datele respective, lacătele sunt scoase unul după altul. De aceea, prima fază se mai zice şi faza de creştere (a numărului de lacăte puse), în timp ce a doua se zice faza de restrângere. Datorită experienţei oferite de bd distribuite însă, s-a dovedit că această variantă iniţială încă nu garantează serializabilitatea! Pentru a o obţine, mai este necesară adăugarea unei noi restricţii: scoaterea lacătelor nu se poate face decât la terminarea tranzacţiei (aşa încât faza de restrângere ar putea fi mai plastic denumită fază de dezumflare). Necesitatea acestei restricţii suplimentare poate fi ilustrată cu ajutorul exemplului 9.3 (de unde se poate observa că problema este mai generală, nu doar pentru bd distribuite, chiar dacă riscurile apariţiei unei situaţii similare cresc exponenţial de la platforme uni-procesor neinterconectate, la mediile de procesare paralelă şi apoi la bd distribuite): Exemplul 10.3
Fie următorul scenariu de execuţie a două tranzacţii T şi T’: Timp Eveniment SGBD t1 T obţine un lacăt exclusiv pentru A t2 T actualizează A t3 T eliberează A t4 T’ obţine un lacăt exclusiv pentru A t5 T’ actualizează A t6 T’ se termină, eliberând A t7 T abortează Evident că, la prima vedere, ambele tranzacţii satisfac varianta iniţială a protocolului de blocare în două faze; însă deoarece T abortează după scoaterea lacătului asupra lui A, SGBD este obligat să ceară un lacăt asupra lui A (în numele T!) pentru a “desface” tranzacţia ce a abortat, ceea ce violează de fapt chiar varianta iniţială a protocolului (căci se cere un lacăt în faza a doua). Mai mult, pentru a “desface” T, SGBD “desface” implicit şi T’ (căci A revenind la vechea valoare dinaintea actualizării sale de către T, actualizarea făcută de T’ se pierde!), lucru ce afectează integritatea datelor (deoarece T’ terminându-se normal nu mai este executat din nou). Rezultă de aici necesitatea restricţiei suplimentare de eliberare a lacătelor doar la terminarea tranzacţiei. Exemplul precedent demonstrează desigur şi faptul că protocolul ce implică stabilitatea cursorului nu este serializabil (căci nu menţine lacătele până la terminarea tranzacţiei).
24
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Blocaje fatale Ca în orice alt tip de control al concurenţei utilizând mecanisme de blocare şi SGBD trebuie să evite o potenţială problemă majoră: blocajele fatale (“deadlocks”). Un asemenea blocaj poate apărea ori de câte ori fiecare dintre tranzacţiile concurente la un moment dat sunt în aşteptarea (circulară) a alteia dintre ele. Cel mai simplu exemplu este cel cu doar două tranzacţii concurente, dintre care prima a blocat data d1 şi aşteaptă să poată bloca şi data d2, iar cea de-a doua a blocat data d2 şi aşteaptă să poată bloca şi d1. Evident că, în acest caz, nici una dintre ele nu mai poate continua vreodată, iar sistemul este blocat în mod fatal (numai o repornire a sa putând debloca situaţia, desigur cu pierderile de informaţii şi integritate a datelor aferente). Majoritatea SGBD vechi, tratează această problemă potenţială oferind mecanisme de detectare a blocajelor fatale; în cazul în care se detectează un asemenea blocaj, sistemul îl “sparge” abortând una dintre tranzacţii (de obicei cea care reuşise să lucreze cel mai puţin până în acel moment), ceea ce permite celorlalte tranzacţii să continue lucrul, urmând ca tranzacţia abortată pentru deblocare să fie apoi imediat repornită. SGBD mai performante, din noile generaţii, oferă mecanisme de prevenire a blocajelor fatale: toate lacătele necesare unei tranzacţii la un moment dat pot fi cerute şi se garantează sau se resping simultan, în mod atomic (în bloc). Desigur că preţul evitării apariţiei blocajelor fatale în acest mod este însă reducerea concurenţei. În cazul exemplului de mai sus, presupunând că prima tranzacţie a cerut şi obţinut blocarea simultană a datelor d1 şi d2, cea de-a doua tranzacţie nu le va mai putea bloca până când prima nu le eliberează. Prevenirea blocajelor fatale este făcută de SGBD prin menţinerea unor “grafuri de aşteptare” (“wait-for graph”) orientate: în ele sunt memorate atât tranzacţiile care au obţinut lacăte, cât şi cele care sunt în aşteptare deoarece au cerut lacăte ce nu pot fi momentan garantate. Nodurile unui astfel de graf memorează identificatorii tranzacţiei şi ai datelor blocate sau a căror blocare e cerută, precum şi tipul lacătului, în timp ce orice arc orientat indică dinspre o dată blocată de o tranzacţie către o altă tranzacţie ce aşteaptă blocarea aceleiaşi date. Evident că orice buclă închisă într-un asemenea graf indică un blocaj fatal. Sarcina SGBD este deci de a preveni mereu închiderea vreunei bucle.
Blocaje fatale globale în bd distribuite Prevenirea blocajelor fatale în bd distribuite este mult îngreunată de posibilitatea apariţiei blocajelor fatale globale, interservere. Exemplul 10.4 analizează o asemenea posibilitate: Exemplul 10.4
Fie două servere distribuite aflate la locaţiile L, respectiv M. Fie o tranzacţie T ce se execută la L şi are nevoie la un moment dat de a actualiza nişte date ale M, înainte de a putea continua execuţia. SGBD L iniţializează pentru aceasta la M o “tranzacţie cohortă” T’ care trebuie să actualizeze datele de acolo din partea T. Să presupunem că, pentru aceasta, T’ are nevoie să pună un lacăt ce nu poate fi deocamdată garantat de SGBD M, deoarece o altă tranzacţie U a blocat datele respective în prealabil. Lucrurile se complică în momentul în care şi U, printr-o tranzacţie cohortă U’, doreşte să blocheze date ale L deja blocate de T! Evident că acest blocaj fatal global nu poate fi prevenit de nici unul din grafurile de aşteptare de la L sau M, care nu conţin nici o buclă, deoarece ele nu au cum să reprezinte arcele de la T la T’, respectiv de la U la U’. O posibilă soluţie pentru prevenirea acestui tip de blocaje este, desigur, introducerea unui gestionar global, centralizat al lacătelor, care să menţină un unic graf de aşteptare pentru întreaga bd
25
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 distribuită. Dezavantajele sunt pierderea autonomiei locale şi, mai ales, aglomerarea traficului în reţea, plus riscurile inerente dependenţei de un singur server. Cea mai interesantă propunere alternativă pare cea avansată, încă din 1982, de cercetătorul Ron Obermark de la IBM [271]: se extinde graful de aşteptări cu un nou tip de noduri care, împreună cu arcele aferente, să memoreze informaţii de tipul “tranzacţia locală T este în aşteptarea terminării tranzacţiei cohortă T’ pe care a iniţiat-o”, respectiv “tranzacţia cohortă U’ este aşteptată să se termine de tranzacţia U ce a iniţiat-o”. Apariţia unui asemenea tip de nod într-un graf de aşteptare este considerată de SGBD drept un potenţial de blocaj fatal global şi declanşează imediat trimiterea subgrafului de aşteptare relevant celuilalt SGBD implicat; acesta, reunindu-l cu graful propriu de aşteptare, poate astfel preveni apariţia vreunui blocaj fatal global. Datorită implicaţiilor asupra traficului de comunicaţii, timpului de execuţie şi spaţiului disc suplimentare ce ar fi necesare implementării acestei soluţii (şi, mai mult, oricăror alte soluţii ce au mai fost propuse) nici un sistem comercial nu oferă însă practic, deocamdată, vreun remediu elegant acestei probleme: dacă un asemenea blocaj apare, SGBD pur şi simplu abortează una dintre tranzacţiile implicate după scurgerea unui interval de timp prestabilit (“time out”) de la blocaj!
Comentarii şi referinţe bibliografice Alături de monografiile generale datorate lui Ullman [336,337] şi Date [122,123], care au şi capitole dedicate acestui subiect, indispensabilă în domeniul controlului concurenţei este excelenta monografie a lui Papadimitriou [276].
Controlul concurenţei în DB2 Pe lângă lacătele uzuale (“tranzacţionale”), DB2 oferă şi “lacăte de drenare“ (“drain locks”), pentru procesarea comenzilor şi utilitarelor de sistem DB2, precum şi “zăvoare” (“latches”), pentru controlul anumitor evenimente interne sistem. Pentru tranzacţii, se pot specifica diverse granularităţi la crearea oricărui spaţiu tabelă; valoarea implicită (ANY) permite SGBD gestionarea automată a acestuia de către sistem prin escalare. Versiunea 3 permite trei niveluri de granularitate: pagină, tabelă, spaţiu tabelă; versiunea 4 adaugă şi nivelul linie. Aceste niveluri nu sunt însă mutual exclusive: în practică, DB2 foloseşte diverse combinaţii de “lacăte de intenţie” (“intent locks”), de nivel spaţiu tabelă şi tabelă, cu lacăte de pagină şi rând pentru a obţine un echilibru cât mai bun între necesităţile conflictuale de asigurare a unei cât mai mari concurenţe şi de evitare a blocajelor fatale. Există trei asemenea tipuri suplimentare de lacăte: “intenţia partajării”, “intenţia exclusivităţii” şi “partajabil cu intenţia exclusivităţii”. Înainte de a obţine un lacăt pe o pagină, DB2 încearcă, în general, obţinerea unui lacăt de intenţie corespunzător. Astfel, • intenţia partajării este cerută pentru operaţiile exclusiv de citire; el permite tranzacţiei tentative ulterioare de obţinere de lacăte non-exclusive asupra paginilor tabelei sau spaţiului respectiv; celelalte tranzacţii pot şi ele citi concurent aceste pagini; • intenţia exclusivităţii este cerută doar pentru operaţiile de scriere asupra mai multor pagini ale unei tabele sau spaţiu de tabele; el permite tranzacţiei cererea ulterioară a oricărui tip de lacăt asupra paginilor; celelalte tranzacţii concurente pot, la rândul lor, obţine orice fel de lacăte asupra paginilor vizate; • partajabil cu intenţia exclusivităţii este similar cu intenţia excusivităţii; diferenţa rezidă doar în faptul că celelalte tranzacţii concurente nu mai pot obţine lacăte exclusive pentru scrierea în vreo pagină a tabelei sau spaţiului respectiv; numele lacătului sugerează chiar faptul că acesta este o conjuncţie a două lacăte: partajabil (care împiedică deci obţinerea unui lacăt exclusiv de vreo altă tranzacţie) şi intenţia exclusivităţii. Pe lângă avantajele deja menţionate, lacătele de intenţie simplifică şi munca sistemului, reducând timpul pierdut de acesta pentru a putea decide garantarea sau nu a unui nou lacăt: ele
26
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 “factorizează” într-un sens tipurile de blocaj concomitent posibile asupra paginilor unei tabele/spaţiu şi scutesc DB2 să analizeze, de fiecare dată, lacătele tuturor paginilor implicate. Programatorii pot decide modul iniţial de blocare folosit de sistem cu instrucţiunea LOCK TABLE; astfel, ei pot cere direct un lacăt partajabil sau exclusiv asupra oricărei tabele (pentru spaţii de tabele segmentate se pot obţine astfel doar lacăte cu intenţie partajabilă, respectiv exclusivă asupra spaţiului, pe lângă lacătul cerut asupra tabelei). Clauza LOCKSIZE a instrucţiunii CREATE TABLESPACE împiedică sistemul să garanteze pentru spaţiul respectiv lacăte de granularitate mai fină decât cel specificat; de exemplu, LOCKSIZE OF TABLE inhibă lacătele de pagină şi linie. Versiunea 3 permite şi controlul blocării fişierelor index prin clauza SUBPAGES a instrucţiunii CREATE INDEX: valorile admise pentru ea (1, 2, 4, 8 sau 16) cer sistemului partiţionarea fiecărei pagini a indexului într-un număr corespunzător de subpagini; lacătele sunt apoi cerute şi garantate pe câte o subpagină. Versiunea 4 foloseşte indexuri de tip 2 (vezi capitolul 14) care nu mai permit blocarea utilizator a indexurilor; aceasta se face automat, numai de sistem, cu ajutorul “zăvoarelor”. DB2 foloseşte stabilitatea cursorului pentru a se asigura că lacătele partajabile asupra paginilor sunt ţinute doar atâta timp cât se citeşte din pagina respectivă; citirile repetabile garantează în schimb că toate lacătele de pagină puse de o tranzacţie sunt menţinute până la terminarea acesteia. Versiunea 4 oferă în plus un nivel nou de izolare: “citirea datelor neterminate” (“uncommitted read”). Acesta asigură o concurenţă mai mare decât stabilitatea cursorului şi semnifică faptul că tranzacţia poate citi date a căror modificare (de către o altă tranzacţie) nu a fost încă terminată. Pentru cazurile în care programatorii nu folosesc corect instrucţiunile ACQUIRE/RELEASE de punere/scoatere simultană a tuturor lacătelor necesare la un moment dat (ceea ce poate conduce la blocaje fatale), DB2 menţine grafuri de aşteptare pentru a preveni automat asemenea situaţii limită; în caz de potenţial blocaj, DB2 selectează dintre tranzacţiile implicate o “victimă”, pe care o “desface”, dând-o înapoi şi eliberează astfel resursele pentru celelalte tranzacţii concurente.
Controlul concurenţei în NonStop SQL Procesele disc interne ale NonStop SQL al Tandem sunt folosite şi pentru gestiunea lacătelor; deşi ele utilizează peste 20 de tipuri de lacăte, extern, programatorilor le sunt vizibile doar cele două clasice (partajabil şi exclusiv). Granularitatea lacătelor include linia, toate liniile unei tabele care au aceeaşi valoare a prefixului cheii (nivel numit “generic”) şi partiţia; pentru a bloca o întreagă tabelă este nevoie de blocarea tuturor partiţiilor sale. Pentru nivelul generic este, evident, neapărat necesară specificarea parametrului de “lungimea lacătului” (“lock length”): numărul de caractere/cifre al prefixului dorit din cheie. Acest nivel este desigur comparabil cu lacătele de pagină ale DB2; diferenţa uriaşă este dată de caracterul sintactic, fizic şi fix dpdv al lungimii pentru pagini DB2, în comparaţie cu caracterul semantic, logic şi de lungime variabilă (ca număr de linii blocate, nu doar ca lungime a lacătului!) asociat nivelului generic din NonStop SQL. Pe lângă stabilitatea cursorului (zisă aici “acces stabil”) şi citirea repetabilă (zisă “acces repetabil”) mai este oferit un nivel suplimentar de izolare: “acces inspecţie” (“browse access”). Tranzacţiile operând în acest mod nu au nevoie de nici un lacăt; ele pot doar citi orice date, inclusiv cele tocmai în curs de modificare de către o altă tranzacţie (ca atare, nu acesta este modul implicit de acces!); evident însă că acest mod de acces contribuie decisiv la mărirea concurenţei, chiar dacă trebuie folosit doar de tranzacţiile ce nu depind critic de valorile exacte ale datelor. Optimizatorul NonStop SQL (vezi capitolul 15) alege şi gestionează automat, folosind la nevoie escalarea, lacătele necesare. Totuşi, sistemul permite utilizatorilor (cu ajutorul instrucţiunii CONTROL TABLE) să controleze durata lacătelor (zise, în acest caz, “lacăte silite”, în engleză “bounce locks”), tipul lor şi nivelurile de izolare. Dacă sistemul are nevoie de o resursă blocată cu un
27
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 lacăt silit, el nu aşteaptă însă pur şi simplu eliberarea resursei ci semnalează aplicaţiei o eroare (excepţie); aceasta va lua măsurile pe care le crede de cuviinţă în contextul respectiv. Operând mai degrabă la nivelul instrucţiunilor SQL (decât la nivelul liniilor, tabelelor sau tranzacţiilor), lacătele silite permit programatorilor scheme de blocare mai sofisticate decât cele automat implementate de sistem. Blocajele fatale sunt rezolvate doar prin “time out” (nu cu grafuri de aşteptare)!
Controlul concurenţei în Oracle Oracle foloseşte şi el foarte multe lacăte şi “zăvoare” interne. Cele externe, vizibile utilizatorilor, sunt numite “lacăte de date” (sau “lacăte DML”). Granularitatea lor depinde de valorile parametrilor de iniţializare ROW_LOCKING şi SERIALIZABLE. Implicit, ROW_LOCKING este ALWAYS, dar el poate fi setat la valoarea INTENT (ceea ce permite citiri concurente ale tabelei, dar obligă la scrieri serializabile, în timp ce ALWAYS serializează doar scrierea unei aceleiaşi linii!). SERIALIZABLE este FALSE implicit, dar poate fi setat la TRUE (ceea ce elimină şi lacătele partajabile la nivel de linii, rămânând disponibile doar lacătele de nivel tabelă). Oracle este unic în modul de rezolvare a controlului concurenţei asupra liniilor din tabele: el nu împiedică citirea datelor în timpul actualizării lor, fără însă a oferi la citire date “murdare”; acest lucru este realizat cu ajutorul unor “fotografii” (”snapshot”) ale datelor făcute ori de câte ori este nevoie iar datele sunt consistente. De exemplu, înainte de a garanta unei tranzacţii blocarea exclusivă a unei linii, aceasta este fotografiată, urmând ca, apoi, în timp ce linia este modificată, tranzacţiile care doresc să o citească să îi aibă la dispoziţie fotografia. Ca atare, la nivel de linie, nu există, de fapt, lacăte partajabile, ci doar exclusive. La nivelul tabelelor există însă următoarele cinci tipuri de lacăte: • Lacătele partajabile pe (grupuri de) linii implică faptul că tranzacţia a blocat un număr de linii al unei tabele pentru a le modifica; ele sunt garantate instrucţiunilor de tip SELECT ... FROM ... FOR UPDATE OF; alte tranzacţii pot actualiza sau obţine lacăte asupra celorlalte linii neblocate ale tabelei, dar nu pot bloca tabela în mod exclusiv. • Lacătele exclusive pe (grupuri de) linii sunt similare, diferenţele constând în faptul că ele sunt garantate instrucţiunilor INSERT, UPDATE şi DELETE şi că celelalte tranzacţii nu pot bloca tabela nici măcar în mod partajabil. • Lacătele partajabile sunt garantate doar de instrucţiunea LOCK TABLE ... IN SHARE MODE; ele interzic altor tranzacţii să actualizeze tabela; dacă însă nu există tranzacţii concurente care să deţină acelaşi tip de lacăt asupra tabelei, acest lacăt permite obţinerea de lacăte de linie (pentru actualizarea acestora). • Lacătele exclusive cu linii partajabile sunt garantate doar de instrucţiunea LOCK TABLE ... IN SHARE ROW EXCLUSIVE MODE; o singură tranzacţie poate deţine la un moment dat un asemenea lacăt pe o tabelă; ea poate actualiza orice linie a tabelei în timp ce alte tranzacţii le pot citi (direct, sau fotografiile corespunzătoare, după caz); nici o tranzacţie nu poate însă obţine în acest timp vreun lacăt partajabil, exclusiv sau exclusiv cu linii partajabile asupra tabelei. • Lacătele exclusive sunt garantate doar instrucţiunilor LOCK TABLE ... IN EXCLUSIVE MODE; tranzacţia poate scrie, alte tranzacţii pot citi fotografia curentă a tabelei, dar nici o altă tranzacţie nu poate deţine vreun lacăt asupra tabelei. Modelul consistenţei multi-versiune al Oracle impune implicit consistenţa de nivel instrucţiune; ea garantează consistenţa rezultatelor oricărei interogări individuale la momentul începerii
28
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 execuţiei interogării. Aceasta înseamnă, în esenţă, două lucruri: oricât de mult ar dura execuţia interogării, ea va accesa mereu aceleaşi valori ale datelor cu cele care erau memorate la momentul începerii execuţiei ei; pe de altă parte însă, tranzacţiile concurente pot lucra în paralel, inclusiv pentru a actualiza datele procesate de interogare. Acest model se mai numeşte şi tehnica de interogare fără blocaje, deoarece nici cititorii nu blochează scriitorii şi nici invers. Interogările văd mereu date consistente (absolut consistente, nu doar relativ consistente, precum în cazul stabilităţii cursorului) chiar dacă acestea nu sunt cele mai recente. Implementarea acestui model este relativ simplă: ori de câte ori o tranzacţie se termină, în jurnalul de actualizări corespunzător este memorată şi valoarea curentă a unui număr de schimbări sistem (SCN) care, apoi, este imediat incrementată; fiecare bloc de date memorat pe disc conţine şi valoarea SCN la momentul ultimei scrieri a datelor blocului respectiv; la momentul începerii execuţiei unei interogări, Oracle memorează valoarea curentă a SCN; atunci când interogarea accesează un bloc de date, acesta este livrat direct dacă SCN-ul său este mai mic sau egal cu cel memorat la începutul tranzacţiei; în caz contrar, Oracle reconstruieşte, cu ajutorul jurnalului de actualizări, o fotografie a datelor conformă cu starea lor la momentul începerii tranzacţiei. Modelul consistenţei multi-versiune poate fi însă schimbat de utilizatori explicit pentru a obliga Oracle să impună consistenţa citirilor la nivelul tranzacţiilor în locul celei de nivel instrucţiune. Aceasta garantează tuturor instrucţiunilor unei tranzacţii (în particular, tuturor interogărilor deci) accesul la o versiune consistentă a datelor, ceea ce este comparabil cu citirile repetabile. Pentru tranzacţiile care scriu, este necesară în acest caz obţinerea în prealabil de lacăte exclusive de linii sau de tabelă (interogările componente ce doar citesc date având nevoie numai de lacăte exclusive de linii). Acest lucru determină, desigur, o scădere a concurenţei. Dacă tranzacţiile doar citesc (şi nu au deci nevoie de nici un fel de lacăt exclusiv), ele pot semnala acest lucru, pentru a permite o concurenţă mărită, prin instrucţiunea SET TRANSACTION READ ONLY; ea are ca efect garantarea consistenţei de către Oracle cu ajutorul SCN, similar ca mai sus. Controlul utilizatorilor asupra concurenţei este extins şi în cazul instrucţiunilor SELECT ... FOR UPDATE prin clauza NOWAIT; în prezenţa acesteia, dacă sistemul nu poate garanta imediat lacătul partajabil pe grupul de linii corespunzător, el nu pune tranzacţia în aşteptarea momentului în care acesta va putea fi garantat (ca în cazul implicit, când opţiunea NOWAIT lipseşte) ci semnalează tranzacţiei o eroare, pe care aceasta o tratează cum crede de cuviinţă. Pentru prevenirea blocajelor fatale, Oracle menţine grafuri de aşteptare; dacă este nevoit să aleagă o victimă, atunci îi “desface” doar ultima dintre instrucţiuni, cea care a provocat blocajul, pasându-i un mesaj în acest sens; tranzacţia în cauză poate decide să se “desfacă” integral, sau să aştepte şi să reîncerce apoi instrucţiunea. În contextul bd distribuite, eventualele blocaje globale fatale sunt rezolvate prin “time out”.
Controlul concurenţei în SQL Server al Sybase Granularitatea lacătelor oferite de SQL Server se bazează pe doar două niveluri, pagină şi tabelă, care pot însă interacţiona sinergic oarecum similar cu cazul DB2. Lacătele de pagină pot fi de unul din următoarele patru tipuri: • Partajabil; implicit scos la terminarea instrucţiunii de interogare. • Actualizare; folosit doar în primul pas al unei operaţii de actualizare (de pregătire a scrierii), în care pagina este doar citită în memorie; în acest răstimp, alte tranzacţii pot citi şi ele pagina; când tranzacţia a terminat actualizarea datelor în memorie, înainte de a le scrie pe disc trebuie să obţină un lacăt exclusiv asupra paginii.
29
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 • Cerere; atunci când o tranzacţie are de scris o pagină şi nu are timp de aşteptat după tranzacţiile care citesc, poate cere un asemenea lacăt; sistemul o va promova în capul listei de aşteptare şi nu va mai garanta nici un alt lacăt partajabil asupra paginii până când tranzacţia nu termină de scris. • Exclusiv; nu este scos până la sfârşitul tranzacţiei. Lacătele pentru tabele sunt de cinci tipuri: • Partajabil, similar cu cel de nivel pagină. • Cerere, idem. • Exclusiv, idem, cu observaţia că, în general, blocarea exclusivă se face doar la nivel de pagină; numai instrucţiunile UPDATE şi DELETE ce nu referă coloane indexate necesită acest tip de lacăt. • Intenţie de partajare; folosit pentru citiri; proprietarul poate ulterior cere blocarea cu lacăte partajabile a oricăror pagini ale tabelei (ce îi vor fi garantate, evident, doar dacă ele nu sunt blocate exclusiv de vreo altă tranzacţie); el este garantat interogărilor care referă atât coloane indexate, cât şi neindexate. • Intenţie de exclusivitate; folosit pentru scrieri; proprietarul poate încerca ulterior obţinerea de lacăte de scriere pentru oricare pagină a tabelei (ce vor reuşi, desigur, doar dacă paginile respective nu sunt blocate de alte tranzacţii), dar şi de lacăte partajabile sau de actualizare; el este garantat pentru inserţii, dar şi pentru actualizări şi ştergeri dacă acestea referă coloane indexate. SQL Server încurajează utilizarea de lacăte de pagină, pentru mărirea concurenţei; dacă totuşi o singură instrucţiune blochează mai mult de 200 de pagini ale unei tabele, sistemul escalează automat lacătul la cel de tabelă. O procedură memorată sistem permite administratorilor modificarea valorii variabilei de configuraţie lock ce reprezintă numărul maxim de lacăte ce pot fi simultan garantate de sistem. Implicit, acesta este 5.000; maxim, el poate fi 2 miliarde! Sybase recomandă utilizatorilor să estimeze că, în medie, este nevoie de câte 20 de lacăte per tranzacţie. Altă procedură memorată oferă administratorilor date despre toate lacătele curente, incluzând identificatorii tabelelor şi tranzacţiilor implicate, precum şi tipul lacătelor. O funcţie permite utilizatorilor să menţină lacătele partajabile asupra unei tabele până la terminarea tranzacţiei. Aceasta, coroborată cu instrucţiunea SET TRANSACTION ISOLATION LEVEL 3, oferă suport pentru citiri repetabile. SQL Server menţine grafuri de aşteptare pentru prevenirea blocajelor fatale; drept “victimă” va fi aleasă întotdeauna (pentru a fi “desfăcută”) tranzacţia implicată ce a consumat cel mai puţin timp procesor.
Controlul concurenţei în CA-OpenIngres CA-OpenIngres are un mecanism de control al concurenţei similar cu cel al DB2 şi SQL Server. Lacătele de pagină pot fi doar partajabile sau exclusive, în timp ce cele de tabelă mai pot fi şi intenţie de partajare, intenţie de exclusivitate sau intenţie de exclusivitate cu partajare. Pe lângă acestea, Ingres mai foloseşte un zăvor intern, transparent utilizatorilor, numit “lacăt nul”. Gestiunea lacătelor se face automat, dar unele facilităţi pot fi controlate şi de utilizatori prin instrucţiunea SET LOCKMODE. Astfel, datele pot fi citite şi fără a cere un lacăt partajat, cu SET LOCKMODE SESSION WHERE READLOCK = NOLOCK; desigur că aceasta măreşte concurenţa, scade probabilitatea blocajelor fatale, dar poate oferi date “murdare”, inconsistente. Similar, pot fi escalate explicit lacătele de pagină la nivelul tabelei, sau poate fi modificat pragul de escalare automată de către sistem (implicit, acesta este de 10 pagini blocate per tabelă).
30
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Cu aceeaşi instrucţiune, utilizatorii pot obliga sistemul să nu aştepte la infinit garantarea unui lacăt, ci doar în limita valorii indicată de opţiunea TIMEOUT; la scurgerea acestui interval de timp, sistemul “desface” instrucţiunea curentă a tranzacţiei în aşteptare şi îi semnalează o eroare; tranzacţia o va procesa cum crede de cuviinţă (reîncercând instrucţiunea “desfăcută” sau renunţând şi “desfăcânduse” complet). Ingres suportă opţional stabilitatea cursorului, deşi citirile repetabile sunt implicit asumate. De asemenea, sunt prevenite blocajele fatale; victima aleasă este complet “desfăcută”, lucru memorat în jurnalul de actualizări.
31
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
3. SALVĂRI ŞI RECUPERAREA DIN EROARE Un alt rol important al SGBD este prevenirea pierderii de date, ceea ce implică existenţa unor facilităţi de salvare regulată a datelor şi de recuperare din erori. Majoritatea SGBD oferă utilizatorilor două tipuri de salvări: integrale (un întreg fişier sau o întreagă bd) şi parţiale (sau incrementale, în care sunt salvate doar datele ce au fost modificate de la ultima salvare integrală). Desigur că salvările integrale sunt mult mai costisitoare, atât ca spaţiu de memorare cât şi ca timp necesare, în raport cu cele incrementale; ca atare, primul tip este folosit mai rar (de obicei săptămânal sau chiar lunar), iar cel de-al doilea mult mai frecvent (zilnic). Strategiile de salvare a datelor sunt foarte diferite de la SGBD la SGBD; de exemplu, se pot face salvări ale datelor dintr-o tabelă, dintr-un grup de tabele (logic interconectate sau doar create de un acelaşi utilizator), dintr-o bd sau dintr-o colecţie de bd. Unele SGBD salvează doar datele propriu-zise, în timp ce altele adaugă şi alte informaţii (de exemplu, restricţiile de securitate asociate). SGBD evoluate măresc performanţa lucrului oferind salvări în timp real (“on-line”) pentru bd care trebuie să fie disponibile clipă de clipă. Folosind salvările (integrale şi/sau parţiale) SGBD pot reface starea bd corespunzătoare ultimei salvări, asigurând astfel cea mai banală recuperare din erori cu putinţă. Aceasta însă nu poate fi întotdeauna mulţumitoare, căci readucerea bd în starea din momentul erorii poate fi foarte costisitoare dacă salvările nu sunt suficient de recente. Ca atare, pe lângă salvări, SGBD menţin în plus şi jurnale de actualizări.
Jurnale de actualizări Un jurnal de actualizări memorează modificările datelor dintr-o bd; el este de obicei memorat tot pe disc dur, într-un fişier separat de cele ale bd (plasat adesea, pentru mărirea siguranţei, pe un alt disc decât cel pe care rezidă bd). Unele SGBD oferă chiar precauţia menţinerii câte unui jurnal oglindă, copie fidelă a fiecărui jurnal, memorată pe alt disc decât jurnalul original, pentru maximă securitate. Deşi nu există nici în cazul jurnalelor de actualizări vreo soluţie standard, majoritatea SGBD memorează în aceste jurnale momentul începerii şi terminării execuţiei fiecărei tranzacţii, ca şi vechile şi noile valori ale datelor pentru fiecare actualizare de date în parte (evident împreună cu numele tranzacţiei corespunzătoare). Cum toate scrierile pe disc se fac grupat, pe zone tampon relativ mari (pentru a mări viteza prin micşorarea numărului de accese la disc), în scopul măririi siguranţei în exploatare unele SGBD oferă protocoale de jurnalizare “înainte de scriere” (“write-ahead”) care forţează scrierea pe disc a înregistrărilor din jurnal înainte de actualizarea corespunzătoare a datelor. Asemenea protocoale evoluate asigură astfel posibilităţi de recuperare din eroare imediată, de exemplu în cazul erorii la scrierea noii valori a unei date pe disc. Majoritatea SGBD evoluate oferă şi posibilitatea de jurnalizare selectivă, prin inhibarea şi repornirea la cerere a jurnalizării. Inhibarea jurnalizării măreşte sensibil viteza sistemului, cu riscul imposibilităţii recuperării automate din eroare. Ea este însă necesară nu doar în teste, ci şi în cazurile în care viteza este critică (exemplu: datele prelucrate sunt imagini, care ocupă foarte mult spaţiu de memorare) iar riscul acceptabil.
Refacerea şi “desfacerea” automată a actualizărilor 32
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Jurnalizarea şi salvarea permit SGBD recuperarea din eroare completă şi automată prin refacerea stării bd dinaintea erorii: după restaurarea bd cu ajutorul copiilor salvate (în cazul în care acest lucru este necesar), refacerea actualizărilor bd se poate face, trivial, parcurgând jurnalul respectiv “de la cap la coadă” şi refăcând corespunzător datele pentru toate tranzacţiile care se şi terminaseră; restul tranzacţiilor sunt apoi repornite. Mai mult însă, jurnalizarea permite şi “desfacerea” actualizărilor (“undo”) produse de tranzacţii, prin parcurgerea jurnalului în sens invers şi efectuarea modificărilor inverse corespunzătoare (“rollback”) asupra datelor actualizate de tranzacţiile “de desfăcut”. Această facilitate, extrem de utilă, poate fi necesară de exemplu pentru a înlătura efectele execuţiei parţiale ale unei tranzacţii care a fost abortată (sau s-a terminat neaşteptat) sau chiar pe cele ale unei tranzacţii care s-a executat integral dar ale cărei modificări în date conduc la violarea constrângerilor de integritate ale bd.
Puncte de verificare Aşa cum am menţionat mai sus, pentru a mări performanţele sistemului (având în vedere viteza mult mai scăzută a acceselor la disc în raport cu cele la memoria RAM) SGBD nu scriu pe disc fiecare actualizare imediat, ci le grupează, folosind zone tampon relativ mari, astfel încât actualizările sunt de fapt memorate doar în RAM şi scrise pe disc mai târziu, mai multe deodată. De exemplu, chiar în absenţa unui protocol de jurnalizare înainte de scriere, este posibil ca sfârşitul unei tranzacţii să fie scris în jurnal fără însă ca ultimele actualizări (poate chiar toate!) să fie şi ele scrise pe disc (acest lucru urmând a se face ulterior, la umplerea zonei tampon corespunzătoare). Pentru a scurta timpul necesar refacerii actualizărilor la recuperarea din erori, unele SGBD folosesc “punctele de verificare” (“checkpoints”): acestea sunt înregistrări în jurnalele de actualizări făcute în momente în care sistemul a forţat scrierea pe disc prealabilă a tuturor zonelor tampon din memorie. În caz de eroare, vor trebui evident refăcute doar actualizările ulterioare ultimului punct de verificare. Cu cât sunt mai frecvente aceste puncte de verificare, cu atât mai scurt este timpul de refacere a bd; desigur însă că fiecare punct de verificare în parte încetineşte viteza de procesare a tranzacţiilor. Ca atare, ele trebuie cerute sistemului de către administratorii săi în mod regulat (de obicei la intervale fixe de timp sau imediat după terminarea unui număr fixat de tranzacţii) dar astfel încât să se optimizeze performanţele globale ale sistemului. Punctele de verificare permit recuperarea din eroare automată, chiar transparentă utilizatorilor, fără a face apel la copiile de salvare ale bd afectate, aşa cum se poate observa din exemplul următor: Exemplul 11.1
Să considerăm scenariul propus de figura 11.1. În acest caz, pentru a recupera din eroare, sistemul trebuie să parcurgă următorii paşi: • Refacerea tuturor actualizărilor făcute de tranzacţiile terminate după ultimul punct de verificare (dar, desigur, înaintea căderii sistemului); referindune la figura 11.1, aceasta implică tranzacţiile 1, 3 şi 6. Acest lucru este necesar deoarece nu este sigur că toate actualizările produse de aceste tranzacţii au şi apucat să fie scrise pe disc (ele putând fi scrise doar în zonele tampon din memoria volatilă). • Ignorarea tuturor tranzacţiilor terminate înainte de ultimul punct de verificare (ce garantează că modificările lor au fost scrise pe disc în întregime); este cazul tranzacţiei 2 din figură.
33
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 • “Desfacerea” actualizărilor făcute de toate tranzacţiile active în momentul căderii sistemului (tranzacţiile 4 şi 5 din figură); cum aceste actualizări sunt parţiale, păstrarea lor ar putea lăsa bd într-o stare inconsistentă! •
Repornirea tranzacţiilor active (4 şi 5) în momentul căderii sistemului.
34
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Tranzacţii 1 2 3 4 5 6
• • • •
axa timpului
Punct de verificare
Cădere sistem
(“•” reprezintă terminarea execuţiei tranzacţiei) Figura 11.1 Un posibil scenariu necesitând recuperarea din eroare
Recuperarea din dezastre Recuperarea din dezastre (naturale, precum cutremure, erupţii vulcanice, inundaţii, uragane etc. sau datorate omului, ca incendii, atentate cu explozibili, întreruperea pe termen lung a alimentării electrice etc.) necesită precauţii speciale pentru bd critice, care trebuie să fie permanent în serviciu (precum cele deservind automatele de eliberare a banilor). În general, este adoptată soluţia existenţei unei alte platforme similare de calcul, de rezervă, aflată într-un alt loc (alt oraş sau chiar altă ţară), care “dublează” sistemul principal în funcţiune. Desigur că aceasta implică două considerente la fel de importante: sistemul de rezervă trebuie să aibă mereu datele cât mai recente în raport cu sistemul principal (lucru care se realizează prin mecanisme de replicare a datelor şi jurnalelor de actualizări) şi să poată prelua rapid procesarea tranzacţiilor de la acesta în caz de dezastru.
Comentarii şi referinţe bibliografice Considerăm suficientă pentru acest subiect o singură referinţă bibliografică, de exemplu [73] sau [166]. Toate SGBD analizate în această secţiune, cu excepţia CA-OpenIngres, oferă facilitatea suplimentară de a defini “puncte de salvare” în orice programe (aplicaţii, proceduri memorate, trăgaciuri). Acestea au etichete în program şi reprezintă pentru SGBD echivalentul unor puncte de verificare pe care programul le poate oricând referi, cerând sistemului “desfacerea” tuturor actualizărilor ulterioare şi revenirea datelor la starea din punctul de salvare dorit.
Salvări şi recuperări în DB2 Salvarea datelor în DB2 al IBM se face, fie total, fie incremental, cu utilitarul COPY. Se pot salva un întreg spaţiu tabelă, o partiţie a sa sau doar o mulţime de date VSAM (“Virtual Storage Access Method”); salvările diferitelor asemenea mulţimi sau partiţii ale unui aceluiaşi spaţiu tabelă se pot face în paralel, pentru creşterea performanţelor. Utilitarul MERGECOPY permite crearea unei singure copii pentru orice spaţiu tabelă, pornind de la o copie totală şi oricâte copii incrementale ulterioare ale acestuia. Datele despre toate salvările făcute sunt memorate în cataloage (vezi capitolul 16). Utilitarul RECOVER TABLESPACE permite recuperarea din eroare a unui spaţiu tabelă, folosind datele din catalog despre salvări, copiile disponibile, punctele de verificare şi jurnalul de
35
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 actualizări. Cataloagele menţin şi date despre punctele de verificare. Restaurarea partiţiilor unui spaţiu tabelă se poate face şi ea în paralel. Pot fi salvate / restaurate şi fişiere index ca şi cataloagele sistem. Pentru mărirea performanţelor, se pot face şi salvări “pe viu” (“on-line”), în timp ce utilizatorii accesează datele respective; dacă aceştia actualizează datele în timpul salvării, acestea se zic “copii spulberate” (“fuzzy backup”), deoarece ele nu pot fi utilizate pentru restaurarea datelor decât în conjuncţie cu jurnalul de actualizări (ce trebuie să aducă la zi valorile datelor modificate după salvare). Jurnalele de actualizări (care se pot menţine în două copii, pentru sporirea siguranţei) memorează atât valorile dinaintea cât şi cele de după fiecare actualizare. Vechile jurnale pot fi arhivate (de obicei pe benzi). Există o mulţime de date VSAM distinsă, numită “bootstrap data set”, care memorează date despre toate jurnalele active şi arhivate, conţinutul lor şi punctele de verificare ce le conţin; ea poate fi listată la cererea administratorului bd. Suplimentar, există şi un utilitar REPAIR care corectează rapid datele inconsistente, pentru ocaziile în care ori e vorba de date neimportante (exemplu, de test), sau se ştie că datele au fost foarte puţin afectate sau atunci când nu este timp pentru recuperarea corectă din eroare; desigur că se impun mari precauţii în acest ultim caz! Preocuparea deosebită a IBM pentru protecţia datelor se manifestă însă de la nivelul hardware: maşinile IBM (pentru care a fost gândit DB2) sunt echipate cu unităţi de control a memorării de tip 3990 Model 6, care suportă atât copiere extinsă de la distanţă (XRC) pentru realizarea de copii “umbră” (“shadowing”) asincrone a volumelor DASD (“Direct Access Storage Device”), cât şi copiere punct-la-punct (“peer-to-peer”) de la distanţă (PPRC) pentru realizarea de umbre sincrone a volumelor DASD. În plus, “RAMAC Array DASD” furnizează un înalt grad de disponibilitate şi toleranţă la erori prin folosirea tehnologiei RAID (“Redundant Array of Independent Disks”). Versiunea 4 a DB2 suportă de asemenea partajarea datelor pe platforma de procesare paralelă IBM “Parallel Sysplex”, pe care pot rula simultan mai multe subsisteme DB2; dacă vreunul din ele devine brusc indisponibil, orice tranzacţie poate comuta cererile sale de acces la un alt subsistem DB2 ce are acces la datele respective.
Salvări şi recuperări în NonStop SQL “Facilitatea de Monitorizare a Tranzacţiilor” (TMF) a fost, până de curând, procesorul specializat al firmei Tandem pentru salvarea şi recuperarea din eroare în NonStopSQL; recent, el a fost înlocuit cu o versiune mai evoluată, NonStop TM / MP (“NonStop Transaction Manager / Massively Parallel”), despre care avem însă foarte puţine date până în momentul redactării acestei lucrări. TMF realizează salvări (inclusiv “spulberate”) / restaurări (prin utilitarele BACKUP / RESTORE) şi gestionează jurnalele de actualizări atât sistem (ale cataloagelor, vezi capitolul 16), cât şi utilizator; acestea conţin valorile dinaintea şi de după fiecare actualizare, precum şi cele relative la punctele de verificare (aici zise “control points”). Pentru siguranţă mărită, jurnalele sunt memorate pe alte discuri decât bd. Recuperarea din eroare se poate face automat sau readucând datele la ultima lor stare consistentă, sau la cea a oricărui moment consistent anterior. “Remote Duplicate Database Facility” (RDF) este o extensie a TMF ce permite utilizatorilor să copieze datele de pe un server aflat la distanţă, astfel încât, în cazul indisponibilităţii bruşte a vreunuia din ele, un alt server să poată imediat prelua şi activităţile acestuia. Una din noutăţile aduse de NonStop TM / MP este cea privind suportul pentru “overflow audit volumes”: pentru a evita oprirea tranzacţiilor din cauza lipsei de spaţiu suplimentar pentru jurnalul de actualizări, acesta monitorizează praguri prestabilite (implicit sau explicit, de către administratorul bd) de umplere a jurnalelor şi, la depăşirea lor, arhivează începutul jurnalului pe un volum “de debordare” special.
Salvări şi recuperări în Oracle Salvarea (inclusiv “spulberată”) şi restaurarea datelor în Oracle se poate face numai cu ajutorul utilitarelor oferite de sistemul de operare gazdă. Oracle gestionează doar jurnalele de actualizări
36
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 şi oferă instrucţiunea RECOVER pentru recuperarea din eroare pe baza jurnalului (ce trebuie, evident, executată doar după restaurarea manuală a fişierelor afectate!). Utilitarele pentru exportul şi importul datelor pot însă servi şi pentru salvarea şi restaurarea datelor; ele permit copii totale sau incrementale (pentru care există şi un utilitar de compactare similar MERGECOPY al IBM) ale tuturor obiectelor unei bd, sau numai toate ori doar unele dintre cele ale unui proprietar oarecare. Jurnalele însă pot fi menţinute în dublu exemplar, simultan pe două discuri diferite, pentru sporirea siguranţei. Pentru un jurnal, se alocă de fapt mai multe fişiere de lungime fixă ce sunt utilizate circular (când unul se umple, sistemul trece la următorul, rescriind astfel cel mai vechi scris dintre ele). Implicit, punctele de verificare sunt constituite doar de momentele în care se schimbă fişierul jurnal curent cu următorul; utilizatorii pot însă specifica şi altele, suplimentare.
Salvări şi recuperări în SQL Server al Sybase SQL Server al Sybase oferă comenzi specializate pentru salvări şi recuperarea din eroare, atât a bd sistem MASTER, cât şi a bd utilizator. Salvarea se face cu DUMP DATABASE ce copiază împreună o bd şi jurnalul asociat; ea poate fi “pe viu”, dar nu poate fi “spulberată”, căci orice cerere de actualizare a datelor ce se salvează trebuie să aştepte terminarea salvării. Dacă jurnalul unei bd rezidă pe alt disc decât bd, comanda DUMP TRANSACTION salvează doar jurnalul, şi şterge din el toate înregistrările privind tranzacţiile terminate. Versiunea 10 oferă în plus un Backup Server capabil să redirecţioneze salvările spre un alt server, aflat la distanţă. De asemenea, el poate reduce considerabil timpul necesar salvărilor prin împărţirea datelor de salvat (“striping”) în maxim 32 de partiţii egale ce pot fi salvate concurent pe tot atâtea dispozitive hardware. Fiecare bd are obligatoriu asociat un jurnal de actualizări ce nu poate fi inhibat nicicând; el memorează valorile dinaintea şi de după fiecare actualizare, precum şi puncte de verificare la intervale regulate de timp. Aceste intervale pot fi modificate indirect de utilizatori prin impunerea unui interval de recuperare maxim; pe baza valorii respective, sistemul calculează cât de dese trebuie să fie punctele de verificare astfel încât recuperarea din eroare să nu dureze vreodată mai mult decât intervalul impus. Comanda DISK MIRROR are ca efect şi duplicarea jurnalelor (împreună cu bd) pe un alt disc; aceasta măreşte sensibil siguranţa şi disponibilitatea datelor (însă cu pierderile de performanţă de rigoare). Comenzile LOAD DATABASE şi LOAD TRANSACTION sunt duale celor similare de salvare şi realizează refacerea bd şi / sau a jurnalelor de actualizări. Pentru a evita blocajele datorate umplerii jurnalelor de actualizări, sistemul forţează pentru fiecare din ele un “prag al ultimei şanse”: dacă spaţiul disc scade sub acest prag, sistemul opreşte temporar toate tranzacţiile şi invocă automat o procedură memorată sistem de salvare a jurnalului; apoi reiniţializează jurnalul şi reia execuţia tranzacţiilor. Administratorii bd şi utilizatorii pot fixa însă praguri proprii, la atingerea cărora sistemul poate lansa automat în execuţie o procedură memorată utilizator care să elibereze spaţiu suplimentar disc. Versiunea 10 oferă o facilitate originală, de neîntâlnit la nici unul dintre celelalte SGBD analizate în lucrare, şi anume posibilitatea de a scrie “tranzacţii structurate” (“nested transactions”) pe subtranzacţii. O subtranzacţie este delimitată de instrucţiunile BEGIN TRANSACTION şi COMMIT, putând conţine în interior oricâte alte subtranzacţii, pe oricâte niveluri de adâncime. În general, o asemenea structurare a tranzacţiilor poate apărea atunci când o aplicaţie are nevoie de sau provoacă execuţia mai multor proceduri memorate şi/sau trăgaciuri, fiecare dintre acestea putând, la rândul lor, invoca sau provoca execuţia altor proceduri memorate şi/sau tranzacţii. De notat însă că, de fapt, sistemul nu consideră terminată nici o subtranzacţie, chiar dacă ea a executat COMMIT, până când tranzacţia înveliş exterior a tuturor subtranzacţiilor astfel structurate nu se termină; dacă aceasta din urmă este “desfăcută” (din orice motiv ar fi) toate tranzacţiile interioare, inclusiv cele ce s-au terminat, sunt “desfăcute” la rândul lor.
37
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Salvări şi recuperări în CA-OpenIngres CA-OpenIngres oferă şi el comenzi pentru salvare (CKPDB, COPYDB şi UNLOADDB) şi recuperarea din eroare (ROLLFORWARDDB). CKPDB creează un punct de verificare, dezactivează intrările aferente din jurnalul de actualizări şi face o copie a bd pe bandă sau disc; copia poate fi şi “spulberată”, caz în care ea va conţine şi toate înregistrările din jurnalul de actualizări ulterioare salvării şi necesare refacerii corecte a datelor. Pentru a preveni debordarea jurnalelor, sistemul le arhivează “pe viu”, continuu: dacă s-a specificat opţiunea WITH JOURNALING a instrucţiunii CREATE TABLE, aceasta înseamnă mutarea înregistrărilor pentru tranzacţiile terminate din jurnalul curent într-unul arhivă; în caz contrar, aceste înregistrări sunt pur şi simplu şterse! Jurnalele memorează atât valorile dinainte şi de după actualizări, cât şi punctele de verificare. Recuperarea din eroare cu ROLLFORWARDDB se face automat, până la momentul căderii, sau înainte de acesta (la cererea administratorului db; în plus, acesta are şi opţiunea de a reface doar tranzacţiile ce au început după o anumită oră a unei zile ). COPYDB permite copierea integrală a tuturor obiectelor proprietate a utilizatorului ce a invocat comanda (i.e. tabele, indexuri, puncte de vedere, proceduri, constrângeri). Aceste date pot fi ulterior restaurate pur şi simplu (adică fără ca, după aceea, sistemul să le mai actualizeze conform vreunui jurnal de actualizări). UNLOADDB permite administratorului copierea integrală a unei bd pentru reîncărcarea ei într-una nouă, vidă; şi acest tip de copie poate fi utilizat pentru restaurări, în aceleaşi condiţii ca şi în cazul COPYDB.
38
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
4. SECURITATEA DATELOR În foarte multe cazuri, nu toţi utilizatorii bd trebuie să aibă acces la orice date. Controlul accesului la date este realizat de SGBD prin posibilitatea acordării de privilegii utilizatorilor autorizaţi. În general, recunoaşterea acestora se face prin câte o pereche de tip (cont/utilizator, parolă), administratorii bd fiind responsabili cu gestionarea privilegiilor garantate utilizatorilor autorizaţi.
Privilegii Tipurile de privilegii oferite de diverse SGBD sunt foarte variate; în esenţă însă, ele includ dreptul de a citi date, a scrie date, a crea noi structuri de date (exemplu: bd sau tabele într-o bd existentă) şi dreptul de a executa anumite programe (utilitare). Privilegiile pot fi garantate implicit (de exemplu, administratorul unei bd poate avea automat dreptul de a crea noi tabele în bd, creatorul unei tabele să scrie şi să citească conţinutul ei etc.) sau explicit (de exemplu, administratorul unei bd poate garanta unor utilizatori dreptul de a crea tabele, altora doar pe cel de a scrie în tabelele existente, unora doar de a le citi, iar restului de utilizatori le poate interzice până şi citirea). Privilegiile sunt de obicei asociate: • tuturor utilizatorilor autorizaţi (“publicul”); de exemplu, majoritatea datelor utilizate în comun de toţi utilizatorii unei bd pot fi oricui accesibile în citire (i.e. datele “publice”, despre tranzacţii bursiere, cursul valutelor, mersul trenurilor sau al avioanelor, cartea de telefon etc.); • tuturor utilizatorilor dintr-un grup (definit de administratorul bd); de exemplu, toţi angajaţii serviciului de contabilitate al unei firme ar putea alcătui un asemenea grup; privilegiile garantate grupului (de obicei de scriere/citire în anumite tabele şi doar de citire în altele) sunt moştenite de toţi membri acestuia (acest tip de privilegiere grupată având, evident, două mari avantaje: poate modela fidel organigrama firmelor şi simplifică munca administratorului bd); • tuturor utilizatorilor sistem (administratori ai bd); de exemplu, pe lângă privilegiul de a avea acces nelimitat la toate datele, acest grup sistem are şi dreptul de a garanta anumitor grupuri sau utilizatori privilegiile de acces la bd, eventual şi pe cel de a transmite acest drept (total sau parţial) altor utilizatori; • creatorilor (proprietarilor) de obiecte; de exemplu, creatorului unei tabele i se poate garanta nu doar dreptul de a scrie/citi tabela respectivă, ci şi cel de a garanta la rândul lui privilegii altor utilizatori asupra tabelei sale; • utilizatorilor individuali; de exemplu, unui utilizator oarecare U, i se poate garanta cu titlu individual (pe lângă eventualele alte drepturi pe care le-ar avea ca membru în unul sau mai multe grupuri) dreptul de a scrie/citi (şi) în tabela T. Privilegiile se pot acorda în unele SGBD doar pentru porţiuni din tabele. De exemplu, orice angajat ar putea citi datele despre colegii săi de colectiv, cu excepţia salariului (accesibil doar şefului de colectiv), fără însă a avea acces la datele despre ceilalţi angajaţi ai firmei. SGBD relaţionale pot oferi asemenea privilegii parţiale foarte uşor prin intermediul “punctelor de vedere” (“view”) diferite asupra datelor.
Codificarea datelor şi verificarea accesului Pe lângă conturi, parole şi privilegii de acces la date, unele SGBD oferă mecanisme suplimentare de asigurare a securităţii datelor. De exemplu, pentru ca datele să nu poată fi modificate sau citite fără a cunoaşte o parolă suplimentară, se codifică (criptează) datele înainte de scrierea lor pe
39
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 disc. SGBD evoluate oferă chiar posibilitatea codificării folosind proceduri de criptare definite de utilizatori. Unele SGBD menţin în plus “dâre de verificare” (“audit trails”), jurnale în care memorează toate activităţile din sistem (inclusiv eventualele tentative de acces neautorizat). Se pot astfel verifica utilizatorii care au modificat (poate chiar criminal!) datele sau au încercat să violeze interdicţiile de acces.
Ierarhia nivelurilor de acces utilizator în bd distribuite Desigur că garantarea securităţii datelor se complică în bd distribuite: este nevoie ca toţi utilizatorii să aibă acces partajabil la toate serverele? are vreunul nevoie de acces exclusiv pe toate serverele? IBM a publicat primul, în 1990 [179], o ierarhie pe patru niveluri de tipuri de acces oferite utilizatorilor, care a devenit între timp aproape un standard în domeniu: • Cereri de la distanţă (“remote requests”): utilizatorii pot citi şi modifica date într-un server aflat la distanţă, dar este permisă o singură instrucţiune SQL per tranzacţie şi per server (deci o instrucţiune nu poate implica decât un server); • Unitatea de lucru de la distanţă (“remote unit of work”): utilizatorul poate citi şi modifica date într-un server aflat la distanţă, dar este permisă o unică tranzacţie, ce poate fi alcătuită din oricâte instrucţiuni SQL, implicând însă doar acel server; • Unitatea de lucru distribuit (“distributed unit of work”): utilizatorii pot citi şi scrie date în mai multe servere per tranzacţie, cu condiţia ca orice instrucţiune SQL a tranzacţiei să facă apel la un singur server; actualizarea datelor pe mai multe servere presupune utilizarea protocolului terminării în două faze (vezi capitolul 13); • Cereri distribuite (“distributed requests”): utilizatorii pot citi şi scrie date în mai multe servere per tranzacţie; orice instrucţiune SQL a tranzacţiei poate face apel la oricâte servere; actualizarea datelor pe mai multe servere presupune utilizarea protocolului terminării în două faze (vezi capitolul 13); optimizarea globală (vezi capitolul 15) este necesară (în special pentru operaţii join şi reuniune multi-server).
Comentarii şi referinţe bibliografice Pentru considerente generale legate de securitatea datelor, recomandăm [71,73,166].
Securitatea datelor în DB2 DB2 al IBM suportă instrucţiunile standard SQL de asignare / revocare a privilegiilor GRANT / REVOKE. Lista sa de privilegii este suficient de granulară pentru a permite administratorilor bd controlul strâns asupra securităţii datelor. De exemplu, un utilizator ar putea primi dreptul de a crea tabele, dar nu şi pe acela al invocării unor utilitare asupra tabelelor respective. Pe lângă aceasta, DB2 împarte utilizatorii în 6 clase: administratori sistem, operatori sistem, administratori de bd, operatori de gestiune a bd, operatori de control ai bd şi public. Fiecare membru al unei asemenea clase moşteneşte automat anumite privilegii. În plus, este oferit şi un “mecanism secundar de autorizare” ce permite definirea de grupuri de utilizatori. DB2 menţine automat şi jurnale de control al accesului.
Securitatea datelor în NonStop SQL NonStop SQL al Tandem nu are mecanisme proprii de securitate (nici măcar nu oferă GRANT / REVOKE din SQL!); el se bazează în această privinţă pe sistemul de operare NonStop Kernel cu care este strâns cuplat. Acesta însă oferă doar privilegii la nivel de fişiere, asemănătoare celor
40
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 din sistemul de operare VMS al DEC (patru privilegii: citire, scriere, execuţie, ştergere; patru clase de utilizatori locali: administrator sistem, proprietar obiect, grup, public; şi trei de utilizatori distribuiţi: proprietar, grup, public).
Securitatea datelor în Oracle Securitatea în Oracle este asigurată în mod standard SQL (GRANT / REVOKE). Trei clase de privilegii diferenţiază trei tipuri de utilizatori: sistem (pentru administratorii bd), obiect (pentru utilizatori individuali obişnuiţi) şi “roluri” (pentru grupuri de utilizatori, deşi, la crearea oricărei bd, Oracle îi asignează cinci roluri sistem). Jurnalele de verificare a accesului sunt activate / inhibate manual (cu comenzile AUDIT / NOAUDIT).
Securitatea datelor în SQL Server SQL Server al Sybase oferă Secure Server, un program ce se conformează standardelor de securitate de nivel B1 şi B2 elaborate de Pentagon. Conform acestuia, utilizatorii trebuie întâi să fie autorizaţi de a lucra cu Secure Server, apoi cu o bd oarecare (privilegiu pe care, de exemplu, un utilizator din categoria “oaspete” nu îl are decât pentru date considerate publice, dacă administratorul bd nu interzice şi aceasta!) şi abia în final cu un obiect al bd respective. Privilegiile sunt numite “permisiuni ”, sunt gestionate în mod standard SQL (GRANT / REVOKE) şi sunt de două niveluri: “comandă” (creare, salvare, interogare, modificare obiecte) şi “obiect” (interogare şi actualizare date într-o tabelă). Ierarhia utilizatorilor include trei tipuri de “roluri” (administratori sistem, ofiţeri de securitate a datelor şi operatori sistem), plus oricâte alte niveluri inferioare de grupuri de utilizatori sau utilizatori individuali obişnuiţi. Versiunea 10 include şi un jurnal de verificare a accesului; diverse proceduri memorate (vezi capitolul 17) permit ofiţerilor de securitate (singurii care au acces la asemenea jurnale!) să urmărească orice încercare de acces, a oricui, la orice obiect.
Securitatea datelor în CA-OpenIngres Şi viitoarea versiune anunţată (1.1) a CA-OpenIngres se va conforma standardelor de securitate C2 ale Pentagonului. Versiunea curentă însă este doar standard SQL (GRANT / REVOKE). Privilegiile sunt granulare, incluzând: selecţie date, inserţie, actualizare, ştergere, toate cele precedente şi execuţie proceduri memorate (care nu necesită nici măcar privilegiul de selecţie a datelor procesate de procedură!). Pentru accesul la Knowledge Manager sunt necesare privilegii speciale suplimentare. Pot fi create grupuri de utilizatori având aceleaşi privilegii; aplicaţiile se bucură sau nu de “roluri” (numele generic al privilegiilor ce pot fi acordate sau nu programelor). Majoritatea bd gestionate de Ingres sunt publice; se pot însă defini bd private, la care au acces doar proprietarul bd, administratorul sistem şi eventualii utilizatori cărora le-au fost acordate privilegii de proprietar (administratorul sistem neavând acest drept). Sunt menţinute şi jurnale de control al accesului, deşi acestea sunt mai degrabă o formă primitivă de jurnale de actualizare (care nu există) în care însă nu sunt memorate instrucţiunile şi/sau valorile modificate, ci doar data şi ora începerii tranzacţiei, identificatorul acesteia, numele utilizatorului, tipul de operaţii efectuate (selecţie, inserţie, actualizare, ştergere) şi identificatorul fiecărei tabele accesate.
41
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
5. IMPUNEREA CONSTRÂNGERILOR DE INTEGRITATE Menţinerea integrităţii datelor este, de departe, cea mai importantă sarcină permanentă a oricărui SGBD. Ca atare, sunt oferite diverse mecanisme de verificare a consistenţei datelor şi de impunere a constrângerilor de integritate. Ne vom focaliza din nou atenţia numai asupra celor mai des întâlnite asemenea mecanisme. Cea mai simplă verificare cu putinţă este cea de încadrare a tuturor valorilor pe care le au datele fiecărei coloane a oricărei tabele dintr-o bd într-un interval de valori (explicit precizat de administratorul bd pentru datele fundamentale sau implicit, pentru cele derivate). SGBD relaţionale oferă în acest scop cel puţin două mecanisme suport pentru integritatea domeniilor (de valori) şi integritatea referinţelor.
Integritatea domeniilor de valori Integritatea domeniilor de valori implementează constrângeri de tip min ≤ x ≤ max, unde min şi max sunt valori dintr-un codomeniu oarecare fixat. Desigur că SGBD evoluate pot impune nu numai faptul că valorile oricărei coloane din orice tabelă trebuie să satisfacă un asemenea predicat, ci şi operatorii ce sunt aplicabili coloanelor în consecinţă. De exemplu, dacă domeniul de valori al unei coloane Sex este M,F , pe lângă restricţia că ‘M’ şi ‘F’ sunt singurele valori admisibile pentru această coloană, SGBD poate deduce că operatorii de egalitate şi non-egalitate sunt acceptabili pentru orice două valori ale acestei coloane (egalitatea fiind necesară, de exemplu, pentru a putea răspunde la o întrebare de tip “Listează toţi angajaţii de sex feminin”) în timp ce toţi ceilalţi operatori relaţionali de comparaţie sau cei de calcul aritmetic nu ar avea sens să fie aplicaţi asupra acestor valori. Implementarea integrităţii domeniilor este de obicei făcută prin specificarea constrângerilor dorite la definirea sau redefinirea fiecărei coloane în parte (constrângeri ce pot fi implicite, atunci când se precizează doar codomeniul, caz în care min şi max sunt cea mai mică, respectiv cea mai mare valoare oferite de acea implementare pentru codomeniul respectiv).
Integritatea referinţelor Ca efect al “propagării cheilor”, al dependenţelor de incluziune sau al constrângerilor de tip sisteme de reprezentanţi (vezi prima parte a lucrări), multe tabele ale unei bd relaţionale conţin coloane de pointeri spre alte tabele sau chiar spre tabela din care fac parte (iar cum pointerii sunt folosiţi şi de SGBD non-relaţionale, problema aceasta este mult mai generală). Valorile dintr-o asemenea coloană (numită şi “cheie străină”) trebuie întotdeauna să fie strict printre valorile unei alte coloane ce face parte dintr-o cheie a unei tabele. De exemplu, coloana Judeţ dintr-o tabelă de Localităţi ar trebui să aibă mereu valori din coloana CodJudeţ, cheie în tabela de Judeţe. Acest tip de constrângere se numeşte integritatea referinţelor. Precizarea şi implementarea integrităţii referinţelor poate fi făcută automat, transparent utilizatorilor, de un SGBD evoluat (şi, de exemplu, Access o şi face aşa). Alte SGBD cer specificarea explicită a fiecărei asemenea constrângeri odată cu (re)definirea coloanei respective, făcând însă apoi automat impunerea lor. Sunt însă şi SGBD care oferă posibilitatea alternativă de impunere a integrităţii referinţelor şi de către proceduri utilizator (de tip “trăgaci”, pe care le vom discuta mai jos) sau numai astfel, fără nici un suport alternativ de impunere automată.
42
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Impunerea integrităţii referinţelor nu este complet trivială, nici măcar în cazul actualizării valorii pointerilor. Astfel, dacă la inserţia unui nou pointer sau la modificarea valorii unuia existent cu o valoare inexistentă în coloana cheie referită de pointer există soluţia simplă a respingerii actualizării respective, un SGBD evoluat ar trebui desigur să întrebe utilizatorul dacă nu cumva doreşte să insereze un nou rând în tabela referită, având noua valoare drept cheie, sau poate doreşte să modifice una dintre valorile cheii referite în noua valoare (în loc de respingerea actualizării, care de multe ori obligă utilizatorul să deschidă şi tabela referită în mod actualizare date, să insereze sau modifice în ea pentru a adăuga noua valoare printre chei, înainte de a se reîntoarce în tabela iniţială pentru a relua operaţia respinsă). Iar dacă modificarea valorilor cheii referite poate conduce la complicaţii (căci s-ar putea cere, din greşeală, modificarea într-o altă valoare deja existentă a cheii, tentativă ce trebuie respinsă desigur), măcar inserarea unei noi chei în tabela referită este o facilitate extrem de simplu de implementat şi care economiseşte mult timp utilizator. În cazul actualizării valorilor unei chei referite (de una sau mai multe coloane) prin ştergerea unei valori existente, în coloanele ce referă cheia respectivă pot apărea probleme de implementare şi mai mari. Astfel, dacă ştergerea ar fi pur şi simplu permisă (ceea ce se întâmplă încă, din păcate, în destule SGBD relaţionale!) toţi pointerii care refereau acea valoare a cheii rămân “în aer”, drept pentru care sunt referiţi ca pointeri “încurcând lumea” (“dangling pointers”). Desigur că cea mai simplă soluţie este de a interzice orice asemenea ştergere. Într-o asemenea implementare însă, dacă ştergerea este uneori chiar necesară, utilizatorul va trebui întâi să şteargă toate referinţele la acea valoare a cheii. S-ar putea deci oferi utilizatorilor posibilitatea de a opta pentru ştergerea automată atât a valorii cheii referite, cât şi a tuturor referinţelor la ea (sau înlocuirea acestora cu referinţe la “obiectul necunoscut” corespunzător). Poate nu chiar atât de evident, însă cu atât mai important de avut în vedere în rezolvarea acestei delicate probleme de implementare a SGBD, este faptul că şi rândurile ce conţin pointeri ce urmează a fi astfel şterşi pot fi, la rândul lor, referiţi de alte chei străine, pe oricâte astfel de niveluri de recursivitate! Mai mult, într-un SGBD ce ar suporta printre constrângeri pe cele de tip sisteme de reprezentanţi (SR), cum ar fi unul construit pe baza MMED (vezi [253] şi prima parte a lucrării), s-ar putea oferi utilizatorilor şi facilitatea de a reorganiza clasele de echivalenţă automat, inclusiv prin splitarea unei clase în mai multe noi clase (mai fine) sau, dual, prin contopirea mai multor clase într-una singură. Evident că asemenea operaţii ridică noi probleme de implementare legate tot de faptul că, în asemenea situaţii, ar fi necesară şi modificarea corespunzătoare a tuturor pointerilor ce referă cheile implicate (iar dacă pentru contopiri acest lucru se poate face complet automat, transparent utilizatorului, în cazul splitărilor este desigur nevoie de consultarea utilizatorului pentru fiecare pointer în parte).
Trăgaciuri Oricâte alte mecanisme de verificare şi impunere a constrângerilor de integritate primitive ar mai oferi un SGBD, el tot trebuie să permită (pentru a putea garanta deplina consistenţă a bd) şi impunerea de constrângeri bazate pe predicate oarecare, ad-hoc. Acest lucru este oferit de majoritatea SGBD sub forma procedurilor de tip “trăgaci” (“declanşator”). Un asemenea trăgaci (“trigger”) este o procedură utilizator (scrisă pentru implementarea unei sau mai multor constrângeri predicative oarecare) căreia i se asociază la definire momentul în care execuţia ei trebuie declanşată automat de sistem. Implementările uzuale specifică pentru aceasta coloana (sau coloanele) în care, dacă se încearcă scrierea unei/unor valori, SGBD “apasă” automat pe “trăgaci”; dacă trăgaciul constată că noile valori nu violează constrângerea pe care el o impune, SGBD va permite scrierea noilor valori; în caz contrar, scrierea este respinsă, iar SGBD obligat probabil să-şi “desfacă” tranzacţia care a atentat astfel la integritatea bd.
Procesarea în două faze a terminării execuţiei tranzacţiilor Pentru a asigura integritatea tranzacţiilor atunci când două sau mai multe SGBD concură la execuţia lor se foloseşte aşa-zisa procesare în două faze a terminării execuţiei tranzacţiilor. De exemplu, în cazul unei tranzacţii de tip transfer electronic al unei sume de bani la distanţă (dintr-un cont
43
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 bancar în altul), trebuie scăzută suma transferată din contul debitor (gestionat de un SGBD1) şi crescută corespunzător suma în contul creditat la distanţă (care este gestionat de un SGBD2). Protocolul în două faze a terminării trebuie să garanteze faptul că cele două SGBD ori au efectuat ambele aceste operaţii, ori nici una dintre ele. În esenţă, acest protocol desemnează un SGBD drept coordonator al execuţiei tranzacţiei, în timp ce celelelalte SGBD implicate trebuie să acţioneze doar ca participanţi la aceasta, supunându-se instrucţiunilor SGBD coordonator. După ce toate instrucţiunile tranzacţiei au fost executate (de către SGBD corespunzătoare) terminarea tranzacţiei are loc în două faze: 1. O fază de PREPARARE a terminării, în care coordonatorul comandă participanţilor să termine tranzacţia, aşteptând apoi (un interval de timp finit, prestabilit) de la fiecare confirmarea posibilităţii terminării acesteia. 2. O fază de TERMINARE propriu-zisă sau de ROLLBACK, în funcţie de confirmările primite de la participanţi. Dacă toţi participanţii implicaţi au confirmat posibilitatea terminării tranzacţiei, atunci coordonatorul emite pentru fiecare în parte instrucţiunea de terminare a acesteia (COMMIT); dacă însă vreun participant nu confirmă (fie din pricina unei erori locale, sau de transmisie, sau a unei căderi complete a sistemului etc.), atunci coordonatorul emite pentru toţi participanţii instrucţiunea de “desfacere” a (dare înapoi, anulare a efectelor) tranzacţiei (ROLLBACK), astfel încât integritatea datelor să nu fie afectată. Nevoia unui asemenea protocol poate apărea atât în cadrul unei unice platforme (rulând două sau mai multe SGBD concurente, vezi cazul platformelor paralele, dar nu doar al acestora), cât şi pentru arhitecturi de platforme interconectate (la distanţă sau local) ale căror SGBD trebuie să coopereze. Particularităţile bd distribuite complică însă mult situaţia şi impun rafinări ale acestui protocol. Pentru a le înţelege, să analizăm următoarele două exemple: Exemplul 13.1
Fie un coordonator şi doi participanţi, ambii răspunzând pozitiv (i.e., gata de terminare) la prima fază. Ca atare, coordonatorul îşi înscrie în jurnal instrucţiunea de terminare COMMIT şi încearcă să o transmită şi celor doi participanţi. Dacă unul dintre ei nu mai poate fi brusc contactat (exemplu, din cauza unei întreruperi a transmisiunilor în reţea), coordonatorul va fi obligat, pentru păstrarea integrităţii tranzacţiei, să încerce în mod repetat transmiterea COMMIT-ului pentru server-ul inaccesibil, până când va obţine de la acesta confirmarea recepţionării ei. Evident că aceasta costă coordonatorul timp de execuţie aproape inutil, căci integritatea datelor este asigurată deja (manipularea datelor de către tranzacţie încheindu-se cu bine). Dar şi server-ul care nu a primit instrucţiunea COMMIT are de suferit, căci nici unul din eventualele lacăte puse de tranzacţia în cauză asupra datelor locale nu poate fi scos până la terminarea ei: ca atare, alte tranzacţii pot fi temporar (dar poate pe termen inacceptabil de lung) blocate în aşteptarea eliberării lacătelor în cauză. Pe lângă complicaţiile ce pot apărea ca urmare a erorilor de transmisie în reţele, sunt desigur posibile oricând şi căderi de sistem ale serverelor locale, ce antrenează şi ele costuri suplimentare pentru menţinerea integrităţii datelor şi tranzacţiilor.
44
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Exemplul 13.2
Să presupunem exact aceeaşi situaţie ca în exemplul 13.1, cu singura deosebire că toţi participanţii au primit instrucţiunea COMMIT, dar unul dintre ei are o cădere de sistem înainte de a apuca să o înscrie în jurnal. La repornire, dacă ar considera tranzacţia respectivă ca neterminată, ar trebui să o “desfacă” înainte de a o lansa din nou, ceea ce ar viola, evident, integritatea datelor distribuite (căci tranzacţia este de fapt terminată pe toate serverele). Ca atare, pentru a hotărî ce tranzacţii s-au terminat de fapt dintre cele aparent neterminate, SGBD repornit trebuie întâi să se consulte cu coordonatorul fiecărei asemenea tranzacţii în parte. Drept urmare, pentru reducerea traficului de mesaje în reţea, au fost aduse două îmbunătăţiri majore acestui protocol: “terminarea presupusă” (“presumed commit”) şi “abortarea presupusă” (“presumed abort”) a tranzacţiilor. În exemplul 13.1 de mai sus, atunci când participanţii confirmă coordonatorului posibilitatea terminării tranzacţiei, ei îşi înscriu în jurnal instrucţiunea de terminare presupusă şi pot astfel scoate toate eventualele lacăte puse de tranzacţie; la rândul său, la primirea tuturor confirmărilor, coordonatorul scrie şi el în jurnal instrucţiunea de terminare presupusă, iar dacă nu mai poate să transmită COMMIT vreunui participant, nici nu mai încearcă acest lucru până la restabilirea comunicaţiilor cu acesta (de care va afla, la un moment dat, ori când va fi reapelat de acel participant, ori când va mai încerca să-l contacteze pentru o altă tranzacţie).
Comentarii şi referinţe bibliografice Constrângerile de integritate au fost introduse de părintele modelului relaţional, distinsul matematician E.F.Codd încă din 1970 [106]. Dependenţele de incluziune ce formalizează integritatea referinţelor au fost introduse abia un deceniu mai târziu de Fagin [136]! Trăgaciurile se datorează echipei System R [27]. Ullman [336,337] şi Date [122,123] dedică capitole întregi problematicii constrângerilor de integritate a datelor.
Impunerea constrângerilor în DB2 DB2 al IBM a fost primul SGBD comercial care a suportat declaraţii de constrângeri vizând integritatea referinţelor (prin clauza FOREIGN KEY a instrucţiunii CREATE TABLE) şi impunerea lor automată. El permite şi specificarea politicii de urmat în cazul cererii de ştergere a unei linii referite: interzicerea ştergerii, ştergerea în cascadă, împreună cu toate referinţele, sau ştergerea doar a liniei respective, cu anularea referinţelor (cu excepţia cazului în care, cel puţin pentru o referinţă dintre cele implicate, valorile nule nu sunt permise; atunci ştergerea este interzisă). Actualizarea valorilor de chei primare referite de vreo linie (printr-o cheie străină) este interzisă; similar, valorile cheilor străine pot fi modificate doar în una din valorile existente ale cheii primare referite. DB2 suportă trăgaciuri; în versiunea 4, verificarea integrităţii domeniilor este extinsă şi la mulţimi de valori enumerate (ce pot fi specificate cu ajutorul clauzei CHECK (nume_coloana IN (mulţime_valori)). Administratorii bd pot suspenda temporar impunerea automată a constrângerilor (de exemplu, pentru a încărca mai rapid o tabelă cu date) pentru o tabelă sau o partiţie a sa; când se doreşte revenirea la normal, invocarea utilitarului CHECK DATA va elimina liniile invalide (ce vor fi plasate în “tabele de excepţii”) şi va informa sistemul despre încetarea suspendării temporare a verificărilor de integritate pentru datele respective.
45
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Impunerea constrângerilor în NonStop SQL Integritatea domeniilor de valori este implementată în NonStop SQL al Tandem prin instrucţiunea CREATE CONSTRAINT; aceasta asociază un nume fiecărei constrângeri şi permite folosirea de expresii logice şi algebrice în definirea lor.
Impunerea constrângerilor în Oracle Oracle permite impunerea constrângerilor de codomenii (exact ca DB2, cu CHECK, care poate însă include şi expresii logice şi algebrice), de integritate a referinţelor (tot ca în DB2, dar fără opţiunea de ştergere cu anularea pointerilor în referinţe) şi trăgaciuri. Trăgaciurile sunt proceduri memorate speciale (vezi capitolul 17) scrise în limbajul de programare extins PL/SQL, care sunt ataşate tabelelor şi se execută automat exact înainte de sau după un eveniment oarecare (exemplu, execuţia unei instrucţiuni INSERT, UPDATE sau DELETE asupra tabelei), o dată per eveniment sau pentru fiecare linie procesată în cadrul evenimentului. Fiecărei tabele i se pot asocia oricâte trăgaciuri, inclusiv incluse unul în altul, ce vor fi executate de sistem într-o ordine arbitrară. Administratorii bd pot suspenda temporar execuţia automată a trăgaciurilor (din considerente de performanţă sau de indisponibilitate temporară a unor date).
Impunerea constrângerilor în SQL Server SQL Server al Sybase oferă doar “reguli” (pentru specificarea integrităţii codomeniilor) şi trăgaciuri (maxim 3 per tabelă, câte unul per INSERT, UPDATE, respectiv DELETE, dar care pot fi recursive -cel mult 16 apeluri- şi pot apela alte trăgaciuri). Începând cu versiunea 10 abia este disponibilă şi impunerea automată a integrităţii referinţelor (dar ştergerile liniilor referite sunt interzise; dacă utilizatorul doreşte altfel, el trebuie să-şi definească, în continuare, un trăgaci corespunzător).
Impunerea constrângerilor în CA-OpenIngres CA-OpenIngres implementează integritatea codomeniilor cu ajutorul instrucţiunii CREATE INTEGRITY (mulţimile enumerate necesită însă o expresie logică disjunctivă, deci de tipul “c = k1 or c = k2 or ... “, unde c este numele coloanei, iar kj sunt elementele codomeniului enumerat!). Trăgaciurile se numesc “reguli” şi sunt deocamdată singurul mod de a cere impunerea integrităţii referinţelor! (abia versiunea următoare şi-a propus, după cum s-a anunţat, automatizarea ei). Particularitatea interesantă însă este generalizarea tipurilor de evenimente ce pot declanşa trăgaciuri, prin posibilitatea specificării de “evenimente semnal de alarmă” (“event alerters”): acestea sunt evenimente externe SGBD (precum, de exemplu, scăderea stocului sau preţului la un produs sub un anume prag) care provoacă însă şi ele execuţia imediată a unei aplicaţii utilizator.
46
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
6. IMPLEMENTAREA FIŞIERELOR INDEX Pentru mărirea performanţei accesului la date SGBD permit definirea şi folosirea fişierelor index. Un index este un fişier asociat uneia sau mai multor coloane dintr-o tabelă (fişier de date) similar indexului din biblioteci de regăsire rapidă a cărţilor (depozitate într-o zonă a unui raft, dintr-o sală, aflată la un etaj, din aripa unei clădiri etc.). În absenţa unui index, SGBD ar trebui să inspecteze secvenţial tabela (fişierul de date) în căutarea oricărei date dorite. Indexurile pot fi automat creaţi de SGBD (pentru cheile tabelelor sau pentru a mări viteza de procesare a interogărilor) sau creaţi la cererea administratorilor sau utilizatorilor bd. Similar, actualizarea lor (pentru a reflecta actualizările datelor indexate) se face automat, transparent utilizatorilor, de marea majoritate a SGBD evoluate, deşi şi acesta poate include comenzi de reindexare la îndemâna utilizatorilor. Ştergerea indexurilor are acelaşi regim: automată, pentru indexurile temporar create de SGBD ori pentru tabelele şterse, sau manuală. La limită, desigur, se pot crea indexuri pentru toate coloanele tuturor tabelelor. Trebuie însă avut mereu în vedere faptul că fiecare index ocupă spaţiu disc şi consumă timp atât pentru crearea, cât şi pentru actualizarea sa. Implicit, SGBD moderne creează automat indexuri pentru fiecare “cheie” (coloană sau mulţime de coloane minimal injectivă; vezi prima parte a lucrării) în parte. Asemenea indexuri sunt zise unice, spre deosebire de cele non-cheie (care admit deci duplicate printre valorile indexate) care se zic neunice. Unele SGBD oferă şi indexuri ciorchine (“cluster”) care asigură performanţe sensibil mărite pentru unele operaţii (exemplu: găsirea tuturor articolelor ştiinţifice publicate pe o temă fixată în ordinea inversă a publicării lor). Aceasta implică ordonarea liniilor din tabelă în ordinea indexului pentru fiecare ciorchine al tabelei (ciorchinele fiind o pagină disc în care sunt memorate mai multe linii). Cel mai rapid acces la date s-ar obţine dacă am putea indica SGBD adresa la care se găseşte pe disc fiecare dintre tuplii pe care dorim să îi accesăm (aşa-zisul identificator al tuplului, prescurtat IDT). Desigur că acest lucru este aproape imposibil pentru un volum mare al datelor, care se şi modifică continuu prin inserarea şi ştergerea de noi linii (articole). Există foarte multe tehnici posibile de implementare a indexurilor; cele mai uzuale dintre ele sunt însă tabelele “talmeş-balmeş” (“hash”), care încearcă doar să calculeze IDT şi arborii B+, care preferă memorarea tuturor IDT.
Accesul “talmeş-balmeş” (“hash”) Deşi este cunoscut şi aplicat de mult, inclusiv de sistemele de operare, descriem şi noi în această subsecţiune mecanismul de acces “talmeş-balmeş” (“hash”), zis şi acces dispersat: În locul IDT al tuplului dorit, utilizatorul poate furniza sistemului doar o cheie de căutare “talmeş-balmeş” a acestuia, pe baza căreia SGBD calculează apoi adresa corespunzătoare. Unică per tabelă, această cheie este constituită din una sau multe coloane ale tabelei (exemplu, pentru o tabelă de angajaţi: numărul de identificare sau numele şi prenumele angajaţilor). SGBD foloseşte o rutină (subprogram) de calcul al unei adrese de memorare unice pentru orice linie a tabelei pe baza valorilor acestei chei de căutare. În SGBD relaţionale, cheia de căutare implicită este cheia (primară a) tabelei. Există mulţi algoritmi pentru transformarea valorilor cheii de căutare în adrese. Cel mai adesea folosiţi sunt cei de tip aritmetic, ce au avantajul vitezei foarte mari de calcul (câteva instrucţiuni aritmetice cu operanzi deja în RAM fiind suficiente); de exemplu, se împarte valoarea cheii (interpretată ca un număr întreg) la un număr prim suficient de mare, iar restul obţinut este considerat a fi adresa dorită. Astfel, valoarea cheii de căutare poate fi direct şi rapid transformată de SGBD în IDT corespunzător.
47
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Obţinerea IDT însă (care trebuie să fie unic pentru orice tuplu!) nu este garantabilă de către algoritmii “talmeş-balmeş”. Desigur că este posibilă coliziunea unor chei, adică apariţia de sinonime (i.e. valori ale cheii pentru care rutina de transformare calculează o aceeaşi valoare). De exemplu, dacă o companie are 50 de angajaţi, identificaţi de numere de la 1 la 50 memorate de o cheie “talmeş-balmeş” ID_Ang definită, pentru economie de spaţiu, ca un număr binar pe 2 octeţi (putând deci identifica 65.536 posibili angajaţi), iar rutina alege drept număr prim pe 47, atunci cheile 1 şi 48, respectiv 2 şi 49, ca şi 3 şi 50 vor fi sinonime, producând coliziuni în calculul IDT. Cea mai frecventă metodă de rezolvare a coliziunilor este gruparea fiecărui grup de sinonime în câte o “găleată” (“bucket”): ori se alocă spaţiu pentru o singură găleată mare, în care sunt memorate toate sinonimele înlănţuite (pe clase de echivalenţă); ori se alocă spaţiu fix pentru fiecare sinonim, iar când o asemenea găleată se umple, ori se măresc toate găleţile (ceea ce ar putea conduce la mari pierderi de spaţiu, căci alte găleţi pot rămâne aproape goale), ori tuplii care ar da pe dinafară sunt memoraţi înlănţuit într-o unică găleată suplimentară (ca în prima variantă). În oricare dintre implementări însă, în caz de coliziune, SGBD trebuie să caute secvenţial în găleata respectivă tuplul dorit (pe baza valorii cheii de căutare). Oricum, accesul de tip “talmeş-balmeş” este util doar în anumite cazuri particulare, pentru acces aleator la câte un tuplu răzleţ; pentru accesul implicând intervale de valori ale unor chei ordonate sau pentru aplicaţii ce solicită sortarea răspunsului (crescător sau descrescător) după valoarea unei chei, arborii B+ sunt mult mai indicaţi. Totuşi, destule SGBD încă mai oferă şi chei “talmeş-balmeş”.
Arbori B+ Arborii B+ sunt structuri de date arborescente special proiectate pentru implementarea indexurilor în bd. Fişierul index propriu-zis este partajat între frunzele arborilor; fiecare frunză conţine mai multe perechi formate dintr-o valoare a cheii indexate şi IDT corespunzător, ordonate (de obicei crescător) după valoarea cheilor. Celelalte noduri (interne) ale arborelui B+, inclusiv rădăcina, sunt constituite de pagini (blocuri); o asemenea pagină conţine întotdeauna maxim k valori ale cheii indexate, intercalate printre k+1 pointeri către nodurile fii ale paginii respective (unde naturalul k este fixat prin calcule de optimizare a vitezei de acces la date prin arbore, ţinând cont atât de minimizarea spaţiului disc ocupat de index, cât mai ales de timpul necesar reorganizării arborelui atunci când se depăşeşte capacitatea de memorare a unei pagini, ca şi de timpul necesar reechilibrării arborelui în urma inserării şi ştergerii de chei indexate). Figura 14.1 oferă un exemplu de asemenea arbore B+; ‘*’ din frunze figurează IDT-uri; se observă că toate nodurile interne conţin succesiuni de tip (pointer1, cheie1, pointer2, cheie2, ..., pointerk+1), unde pointerii sunt figuraţi prin ‘*’ iar semnificaţia oricărui pointerj este următoarea: nodul fiu indicat de acest pointer este ori frunza ce memorează toate valorile cheii indexate cuprinse în intervalul mărginit de cheiej-1 şi cheiej+1, ori o altă pagină conţinând valori ale cheii aflate în acelaşi interval. Dacă pointerul este primul sau ultimul din nod, atunci cheiej-1 respectiv cheiej+1 sunt considerate a fi valorile cheii corespunzătoare din pagina tată a celei curente (adică cea aflată imediat la stânga, respectiv imediat la dreapta pointerului care indică pagina curentă; în cazul rădăcinii, în mod natural, la stânga primului pointer se consideră a fi valoarea minimă posibilă a cheii, iar la dreapta ultimului pointer, dual, se consideră valoarea maximă posibilă a cheii). Principala proprietate a arborilor B+ este echilibrarea: în orice moment, distanţa de la rădăcină la orice frunză trebuie să fie aceeaşi. Aceasta asigură SGBD aceeaşi viteză de regăsire a oricărei valori a indexului şi expansiunea arborelui întâi pe orizontală, la maxim şi abia apoi cu un nou nivel pe verticală (asigurându-se mereu numărul minim posibil de niveluri de căutare); în plus, ea previne degenerarea arborelui într-o listă înlănţuită.
48
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 * 30 * 60 *
*10 * 18 *
2*4*7*8*
11 * 15 * 18 *
pagina rădicină
* 36 * 43 * 51 *
19 * 30 *
* 72 * 85 *
31 * 35 *
37 * 38 * 41 *
44 * 45 * 51 * ..
Pointeri IDT către tuplii indexaţi
Figura 14.1 Un exemplu de arbore B+
Pe lângă un acces suficient de rapid la orice tuplu, fără complicaţii de tip coliziune, arborii B+ sunt extrem de eficienţi pentru accesul implicând intervale de valori ale unor chei ordonate sau pentru aplicaţii ce solicită sortarea răspunsului (crescător sau descrescător) după valoarea unei chei astfel indexate. Mai mult, el permite furnizarea răspunsului la interogările ce implică doar coloane indexate în mod simplu, direct din fişierul index, fără a mai fi necesară consultarea tabelei corespunzătoare (acelaşi lucru e valabil şi pentru joinuri, vezi capitolul 15).
Memorarea grupată a tuplilor în pagini Majoritatea SGBD evoluate optimizează atât spaţiul disc ocupat de bd, cât şi accesul la informaţii memorând grupat tuplii în pagini. Ca atare, IDT sunt de fapt perechi de numere, în care primul indică pagina iar al doilea indică “deplasamentul” (“offset”) tuplului în pagină (i.e. distanţa de la începutul paginii şi până la începutul tuplului). Mai precis, cum numărul de tuplii ce încap într-o pagină este fixat, se rezervă la sfârşitul fiecărei pagini câte o “căsuţă” (“slot”) pentru memorarea deplasamentelor fiecărui tuplu din pagină. Această dublă indirectare are avantajul că, atât timp cât un tuplu este memorat într-o aceeaşi pagină, IDT-ul său nu se modifică (deci nici indexul său nu trebuie modificat, fie el tabelă “talmeşbalmeş”, fie arbore B+), chiar dacă poziţia tuplului în pagină se schimbă. Pe lângă economia de timp astfel realizată, aceasta permite SGBD reorganizarea internă a paginilor memorând tuplii (pentru recompactarea sau sortarea lor) fără afectarea indexurilor.
Comentarii şi referinţe bibliografice “Biblia” structurilor de date, inclusiv deci tabele “talmeş-balmeş”, arbori, sortare etc.[210], rămâne şi astăzi impresionanta serie de volume “Arta programării calculatoarelor” a distinsului matematician american Donald E. Knuth. Arborii B au fost introduşi de Bayer şi McCreight [51] în 1972, neîncetând de atunci să fie perfecţionaţi de nenumărate ori, inclusiv de Bayer [52], dar şi de alţi cercetători, precum Comer [113] sau Rosenberg şi Snyder [300]. Acest lucru va continua probabil mereu, pentru a exploata noile performanţe hardware la dispoziţie şi a mări mereu viteza aplicaţiilor de bd din ce în ce mai complexe.
49
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Cea mai interesantă generalizarea a arborilor B ni se par a fi “căile de acces generalizat la date” propuse de Haerder [168]. Alte texte de referinţă în domeniu includ, desigur, Ullman [336,337] şi Date [122,123].
Fişiere index în DB2 DB2 al IBM foloseşte doar arbori B+ pentru orice index; spaţiile index sunt automat create şi gestionate de sistem la declararea indexurilor de către utilizatori. Pot fi definite indexuri unice, ciorchine şi indexuri compuse (maxim 64 de coloane per index). Versiunea 4 oferă şi aşa-zişii indexuri de Tip 2: ele includ îmbunătăţiri privind blocarea (aceste indexuri nu mai sunt blocate; doar tabelele se blochează!) şi procesarea paralelă (aceste indexuri sunt multi-nivel, nu au subpagini, iar IDT pentru cele neunice sunt sortate pentru mărirea performanţelor în cazul existenţei multor duplicate).
Fişiere index în NonStop SQL NonStop SQL al Tandem creează implicit câte un index (arbori B+) unic pentru cheia primară (ce nu poate conţine valori nule!) a fiecărei tabele (SYSKEY). El permite însă atât tabele neindexate (pentru care însă lungimea liniei nu mai poate fi modificată după introducerea de date în fişier), cât şi tabele “talmeş-balmeş”. Indexurile pot fi unice, ciorchine şi compuse (pentru care nu există restricţia adiacenţei coloanelor componente!). Cea mai interesantă inovaţie în domeniul fişierelor index se referă însă la “indexurile alternative” (orice index, cu excepţia celor pentru cheile primare ale tabelelor): acestea memorează nu doar valorile cheii respective, ci şi pe cele ale cheii primare corespunzătoare! Astfel, desigur, răspunsul la foarte multe interogări poate fi furnizat doar din indexuri, fără accesarea tabelelor propriu-zise.
Fişiere index în Oracle Oracle oferă indexuri bazate pe arbori B*, unice sau neunice, ciorchine şi compuse (maxim 16 coloane per tabelă, nu neapărat adiacente). Accepţiunea despre ciorchini de date este aceeaşi cu cea de la DB2, mai generală decât cea menţionată în prima secţiune a capitolului, în sensul că fiecare ciorchine memorează linii din mai multe tabele legate între ele prin chei externe (de exemplu, toate localităţile dintr-un judeţ sunt memorate împreună cu linia corespunzătoare din tabela de judeţe). Pentru aceasta, utilizatorul trebuie să furnizeze o “cheie ciorchine”, care să indice tabelele ce vor fi memorate astfel împreună. Oracle oferă şi “ciorchini talmeş-balmeş”.
Fişiere index în SQL Server SQL Server al Sybase suportă doar indexarea B+. Este permis un singur index ciorchine şi maxim 249 non-ciorchine per tabelă. Sunt oferite şi indexuri unice şi compuse (maxim 16 coloane).
Fişiere index în CA-OpenIngres Fişierele index ale CA-OpenIngres pot fi partiţionate şi răspândite pe mai multe discuri, pentru mărirea performanţelor sistemului. Se permit indexuri unice şi compuse (maxim 32 coloane per tabelă). Utilizatorii pot alege ei înşişi structura de date dorită pentru fişierele index (dar şi de date!) dintre următoarele: “talmeş-balmeş”, arbori B+ şi ISAM secvenţiale (fişiere sortate, statice, ce nu pot fi actualizate decât prin rescriere; folosite doar pentru date ce suferă modificări extrem de rar).
50
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
7. OPTIMIZAREA PROCESĂRII ŞI ACCESULUI LA DATE De cele mai multe ori există mai multe posibilităţi de a accesa datele dorite dintr-o bd. Orice SGBD care se respectă are încorporat, în consecinţă, un optimizator care o alege pe cea mai bună, la orice moment dat, în funcţie de criteriul dorit. Strategia de acces la date aleasă de optimizator este cel mai adesea decisivă în obţinerea de performanţe cât mai bune. Ca atare, toţi furnizorii de SGBD cheltuiesc enorm pentru perfecţionarea optimizatoarelor cu care îşi dotează produsele. Cea mai costisitoare operaţie cu putinţă asupra datelor este, de departe, join-ul (vezi prima parte a lucrării). Deşi au fost proiectate foarte multe strategii de implementare a sa în diverse condiţii, cercetătorii în domeniu încă mai caută noi soluţii, mai bune măcar în anumite circumstanţe. Este obligatorie, ca atare, începerea acestui capitol cu studiul optimizării join-ului. Mai general, orice acces la date (nu doar cel pentru calculul unui join sau a unei expresii de algebră relaţională oarecare) poate fi uneori optimizat. Principalele două tipuri existente de asemenea optimizări (pe care le vom studia, la sfârşitul acestui capitol în cazul SGBD relaţionale, care le-am introdus şi perfecţionat iterativ) sunt bazate pe reguli, respectiv bazate pe costuri.
Optimizarea operatorului join Dintre diversele variante de implementare a joinului, nu există nici una care să fie cea mai bună în orice context; fiecare din cele analizate în continuare sunt mai bune decât celelalte numai în anumite condiţii. Sarcina oricărui optimizator este ca, pe baza datelor statistice de care dispune (şi, adesea, a unei euristici) s-o aleagă pe cea mai bună dintre ele în orice moment.
Implementarea “buclă în buclă” a joinului Implementarea cea mai simplă, prima care ar veni probabil oricui în minte, este cea de tip “buclă în buclă” (“nested loop”): algoritmul buclează pentru toate liniile din prima tabelă şi pentru fiecare din ele buclează pentru toate liniile din cea de-a doua tabelă în căutarea eventualelor valori comune pentru coloanele implicate în join (urmând, evident, ca la găsirea oricăror două linii din cele două tabele care coincid pentru aceste coloane să genereze o linie în tabela join calculată). Dacă n şi m sunt, respectiv, numărul liniilor din cele două tabele operand, este evident că acest algoritm este costisitor, complexitatea sa fiind proporţională cu n*m. Această metodă de calcul al joinului este, ca atare foarte scumpă dacă tabelele sunt mari; pentru tabele mici însă sau chiar în cazul în care ele sunt mari dar există un index pe coloana join din cea de-a doua tabelă, ea poate fi mai bună decât orice altă implementare.
Implementarea “sort/reuniune” a join-ului Dacă coloanele join ale celor două tabele sunt sortate în aceeaşi ordine (i.e. ambele crescător sau ambele descrescător), algoritmul “buclă în buclă” poate fi imediat îmbunătăţit în mod dramatic astfel: în bucla internă, după găsirea unei egalităţi, se mai continuă scanarea tabelei sortate doar cât timp egalitatea se mai păstrează; la prima linie pentru care cele două coloane join diferă, bucla internă este abandonată şi algoritmul continuă cu următoarea linie (a primei tabele) din bucla externă; profitând şi de sortarea primei tabele, cu ajutorul câte unui cursor pentru fiecare tabelă şi a unei variabile care să ţină minte mereu valoarea curentă (din dreptul cursorului) a coloanei join din cea de-a doua tabelă, se poate optimiza şi bucla externă astfel încât fiecare linie a celei de-a doua tabele să fie citită tot o singură dată pe tot parcursul execuţiei programului.
51
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Evident că astfel pot fi economisite foarte multe accese la a doua tabelă; este trivial faptul că, păstrând notaţiile introduse în secţiunea anterioară, acest algoritm, numit “sort/reuniune” (“sort/merge”), are complexitatea proporţională cu n+m. Deşi aparent el este, ca atare, întotdeauna mai bun decât primul (n+m < n*m, ∀ n,m naturali!), nu trebuie însă uitat că acest algoritm presupune sortarea ambelor coloane de join. Dacă ele sunt deja sortate, această implementare este întotdeauna preferată; în anumite condiţii, chiar atunci când ele nu sunt sortate dar există câte un index pentru fiecare, ea rămâne cea mai bună soluţie. Dacă însă cele două coloane nu sunt sortate, atunci SGBD trebuie să le sorteze în prealabil şi acest cost suplimentar poate face această metodă mai scumpă decât altele. În cazul tabelelor mari în care reuşesc multe comparaţii (i.e. sunt găsite multe egalităţi şi, deci, rezultatul joinului va avea multe linii), “sort/reuniune” rămâne însă cea mai bună, chiar dacă cele două coloane trebuie întâi sortate.
Implementarea hibridă a joinului Una dintre implementările recent propuse pentru join este o combinaţie a celor două metode clasice discutate mai sus, “buclă în buclă” şi “sort/reuniune”, motiv pentru care ea se şi numeşte “hibridă”. Ea presupune că o tabelă are un index pe coloana join, iar cealaltă are coloana join sortată în ordinea acestui index (dacă nu este aşa, atunci algoritmul debutează prin sortarea ei). Cu aceste condiţii îndeplinite, algoritmul hibrid scanează indexul secvenţial, construind, cu algoritmul "sort/reuniune”, un join între tabela sortată şi index (privit ca o tabelă sortată cu două coloane: cheia, coloană join sortată, şi IDT, adică adresa liniei respective în tabela a doua, pentru care a fost construit indexul). Tabela rezultat obţinută este apoi sortată crescător după coloana IDT (a adreselor tuplilor în tabela indexată) iar după aceea, printr-un nou join "sort/reuniune" a acestei tabele intermediare cu tabela indexată (din care se elimină, desigur, coloana IDT) se obţine rezultatul final. De remarcat că fiecare tuplu din cele două tabele operand iniţiale este citit doar o singură dată, ca în metoda "sort/reuniune". Desigur că se adaugă costul operaţiilor intermediare suplimentare ("sort/reuniune" cu indexul şi sortarea tabelei intermediare), dar metoda devine cea mai bună pentru tabele mari cu multe duplicate în coloanele pe care se cere join-ul.
Implementarea “talmeş-balmeş” a join-ului După cum sugerează numele pe care îl poartă, această metodă exploatează viteza foarte mare cu care se pot calcula adrese din valori ale unei chei, prin accesul “talmeş-balmeş” (“hash”, vezi capitolul 14): din ambele coloane join se obţine, cu un acelaşi algoritm “talmeş-balmeş” câte o tabelă “talmeş-balmeş”; în fiecare dintre acestea, valorile egale vor ajunge, evident, în aceeaşi “găleată”. Cele două tabele astfel obţinute (fiecare din ele putând conţine ori doar IDT, adică adresa tuplului respectiv, ori tot tuplul, sau doar coloanele de interes) sunt apoi supuse unui join “sort/reuniune” (desigur, doar pentru intrările lor nevide) care produce rezultatul cerut. Pentru mărirea performanţelor acestui algoritm, se încearcă memorarea ambelor tabele “talmeş-balmeş” în RAM; dacă acest lucru nu este posibil, se încearcă acest lucru măcar pentru una dintre ele. În general, se poate uşor observa că performanţele acestui algoritm scad pe măsura creşterii coliziunilor, în particular deci a numărului de duplicate în coloanele join.
Implementarea folosind semijoin-uri în bd distribuite În contextul bd distribuite, costul transmisiei datelor depăşeşte cel mai adesea cu mult pe cel al procesării lor propriu-zise. Ideea “semijoin”-urilor este tocmai de a optimiza joinul, atunci când cei doi operanzi rezidă pe servere diferite, prin transferul minimului de informaţii cu putinţă (ideal: doar al tuplilor joinabili).
52
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Pentru aceasta, se proiectează întâi una din tabele, de la locaţia A (de regulă, cea mai mică dintre ele, dacă nu intervin alte considerente, vezi secţiunea 15.6) pe coloana join, împreună cu IDT (adresa tuplilor respectivi); tabela cu doar două coloane rezultat al proiecţiei este mutată pe celălalt server B, unde se face un prim join între ea şi cea de-a doua tabelă; astfel sunt eliminate liniile ce nu trebuie transmise (căci nu iau parte efectiv la join). Se poate cere acum transmiterea de la A la B doar a acelor linii care sunt necesare, folosind IDT al acestora; în final, se poate calcula pe A join-ul cerut. Este evident faptul că reducerea costurilor de transfer a datelor astfel obţinută poate fi considerabilă, în special pentru tabele mari.
Alte tipuri de optimizări ale procesării datelor Metodele de implementare a joinurilor analizate în secţiunea precedentă nici nu sunt singurele şi au şi generat diverse variante îmbunătăţite, în special prin utilizarea de fişiere index suplimentare. În plus însă, join-urile sunt rar necesare singure în aplicaţiile uzuale de bd: cel mai adesea, ele sunt doar o parte din expresii algebrice complexe implicând şi selecţii şi proiecţii (SPJ, vezi secţiunea 1.4.4). Deşi nu s-a putut găsi nici un algoritm general de optimizare a oricărei expresii de algebră relaţională, literatura de specialitate conţine atât sugestii utile generale, cât şi un algoritm de optimizare care este folosit, cu sau fără alte îmbunătăţiri minore, de marea majoritate a SGBD pentru evaluarea expresiilor SPJ. Strategiile generale de optimizare includ: • efectuarea selecţiilor cât mai devreme cu putinţă (pentru eliminarea tuplilor ce nu vor mai participa în evaluarea în continuare a expresiei); • pregătirea adecvată a căilor de acces (prin sortări şi/sau creare de indexuri); • memorarea rezultatelor subexpresiilor ce apar repetat într-o expresie (pentru a evita recalcularea lor la fiecare nouă apariţie; în special, este cazul “punctelor de vedere” utilizate repetat, căci definiţia lor e întotdeauna o subexpresie); • evaluarea simultană a selecţiilor şi proiecţiilor adiacente asupra aceleiaşi tabele; • combinarea proiecţiilor cu orice operaţie binară adiacentă (eliminarea unor coloane se poate face simultan cu citirea tabelei respective pentru efectuarea unei alte operaţii); • combinarea produselor carteziene cu acele selecţii adiacente care le pot transforma în join (dacă un produs cartezian este argumentul unei selecţii ce conţine “şi”-uri logice de comparaţii între coloanele operanzilor produsului, acesta se poate înlocui cu un join; de notat că, aşa cum se poate uşor demonstra, un produs cartezian este întotdeauna mai scump decât orice join între operanzii săi; merită semnalat aici de asemenea, că orice comparaţie a selecţiei ce nu implică nici o coloană a vreunuia din cei doi operanzi ai produsului cartezian poate fi mutată înaintea produsului, ceea ce este preferabil chiar transformării acestuia în join!). Folosind strategiile de mai sus, împreună cu legile de asociativitate, comutativitate şi distributivitate ale operatorilor algebrici relaţionali, a fost proiectat algoritmul de optimizare a expresiilor relaţionale menţionat mai sus. În esenţă, construind un arbore sintactic pentru expresia de optimizat, acest algoritm constă din următorii şase paşi: 1. Transformă orice conjuncţie de selecţii asupra unei expresii într-o cascadă de selecţii (asupra expresiei respective). 2. Mută orice selecţie cât mai jos posibil în arbore (spre frunze). 3. Elimină proiecţiile inutile şi împinge toate proiecţiile cât mai jos posibil în arbore (eventual desfăcând unele din ele în două, dacă se poate, ori de câte ori proiecţia nedesfăcută nu mai poate coborî, dar măcar una din componentele sale ar mai putea-o face).
53
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 4. Combină cascadele de selecţii şi proiecţii într-o singură selecţie, o singură proiecţie sau o selecţie urmată de o proiecţie. 5. Partiţionează nodurile arborelui astfel rezultat în grupuri, după cum urmează: fiecare nod interior reprezentând un operator binar (produs, reuniune sau diferenţă) formează un grup ce mai conţine toate nodurile strămoşi adiacente reprezentând operaţii unare (selecţii sau proiecţii), precum şi orice lanţuri de descendenţi unari ce se termină cu o frunză, cu excepţia cazului în care operatorul binar e un produs cartezian ce nu este urmat de nici o selecţie cu care să se poată combina pentru a se transforma în join. 6. Evaluează grupurile independent unul de altul, cu singura restricţie că nici un grup nu poate fi evaluat înainte de vreun grup descendent de-al său.
Folosirea mai multor fişiere index per tabelă: implementarea “index AND” şi “index OR” a selecţiilor Optimizatoarele SGBD moderne exploatează şi posibilitatea de a construi şi menţine mai mult de un fişier index per tabelă, pentru mărirea performanţelor implementării operatorului relaţional de selecţie. Astfel, în cazul unor predicate de selecţie compuse din conjuncţii sau disjuncţii de comparaţii, existenţa câte unui index per comparaţie permite implementarea “index AND”, respectiv “index OR” a selecţiei. Exemplul 15.1
Fie o selecţie asupra unei tabele T al cărui predicat este o conjuncţie de comparaţii, fiecare din acestea implicând câte o coloană diferită (C1 şi C2) şi două constante (k1 şi k2); în SQL, ea ar fi exprimată astfel: select * from T where C1 = k1 and C2 = k2 Să presupunem că SGBD dispune de câte un index pentru fiecare din cele două coloane; dacă optimizatorul ar folosi doar unul dintre aceştia, de exemplu cel pentru C1, ar putea selecta rapid doar toate liniile T pentru care C1 are valoarea k1; multe din acestea însă nu satisfac probabil predicatul de selecţie, neavând valoarea k2 în coloana C2 (şi deci au fost inutil selectate, trebuind a fi eliminate din răspuns într-un al doilea pas). Folosirea concomitentă a celui de-al doilea index ar putea, evident, optimiza implementarea acestei selecţii. Procesarea “index AND” pe care o schiţăm în continuare presupune doi arbori B+ drept indexuri: optimizatorul scanează cele două indexuri, selectând din fiecare doar IDT ai tuplilor ce satisfac comparaţia respectivă (pentru exemplu de mai sus, cei pentru care cheile index au valorile k1, respectiv k2); cei doi vectori (i.e. tabele unicoloană) de IDT astfel rezultaţi sunt apoi intersectaţi, obţinându-se în acest mod un vector ce conţine doar IDT ai răspunsului cerut; pe baza sa, sunt în final citiţi din tabela T doar tuplii corespunzători. Evident că procesarea “index OR” este similară: dacă predicatul selecţiei din exemplul 15.1 ar fi “or” (în loc de “and”), este suficientă înlocuirea intersecţiei cu reuniunea vectorilor de IDT.
54
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Optimizarea accesului la date bazată pe reguli În această abordare, SGBD examinează interogările şi alege strategia de acces la datele necesare evaluării acestora luând în considerare eventualele indexuri existente pentru datele în cauză şi sintaxa interogării. În esenţă, aceasta presupune folosirea indexurilor ori de câte ori ele există (pentru a evita căutările secvenţiale în fişierele de date) şi stabilirea unui set de reguli de optimizare a accesului. Un exemplu de astfel de regulă ar putea fi următorul: dacă accesul la date implică un join pe o coloană a unei tabele pentru care nu există un index, atunci, înainte de calculul join-ului, construieşte un index temporar pe acea coloană. Au fost propuse mai multe asemenea seturi ad-hoc de reguli, fără însă a se putea demonstra pentru vreunul eficienţa sa în general sau măcar în raport cu vreun alt set de asemenea reguli. Mai mult, există puternice indicii că aşa ceva nici nu se poate demonstra vreodată. În plus, orice asemenea set presupune cunoştinţe de specialitate din partea utilizatorilor (ca să poată formula interogări optimizabile) iar orice modificare într-un set de reguli necesită şi modificarea unor tranzacţii (deja scrise, testate şi memorate pentru uzul curent) pentru a beneficia de noile optimizări posibile. Toate aceste considerente fac ca SGBD evoluate să prefere optimizarea bazată pe costuri.
Optimizarea accesului la date bazată pe costuri În această abordare, SGBD consultă întâi statisticile aferente datelor implicate (i.e. dimensiunile tabelelor, existenţa şi tipul indexurilor, cele mai mici şi cele mai mari valori ale cheilor, distribuţia valorilor pentru chei etc.) pentru a estima costurile asociate fiecărei posibile strategii de acces în parte. Statisticile despre date, fiind meta-date, sunt memorate în cataloage (vezi capitolul 16). Actualizarea lor este, în sine, o problemă, căci ar micşora sensibil performanţele sistemului dacă ar fi făcută la fiecare actualizare a datelor implicate. Ca atare, ea se face de către programe utilitare specializate la intervale mai mari de timp, de preferinţă când încărcarea sistemului este minimă. Pentru tabelele foarte mari şi cu multe indexuri ea se poate face, opţional, doar pe baza unui eşantion aleator al tuplilor tabelei (ce poate fi precizat implicit, de sistem, sau explicit, de către administratorul bd). De asemenea, procesul evaluării costurilor şi alegerii strategiei optime corespunzătoare poate fi, la rândul său, foarte costisitor. De exemplu, dacă o aceeaşi tranzacţie este executată frecvent, reconsiderarea completă a optimizării ei de fiecare dată este evitată de SGBD evoluate prin memorarea pe disc, în antetul tranzacţiei, a “programului de optimizare” corespunzător; la o nouă execuţie ulterioară a ei, optimizatorul va avea deja toate căile de acces posibile, precum şi formulele de calcul a costurilor asociate gata “compilate”, urmând doar să refacă calculele pentru valorile curente ale datelor statistice implicate.
Mecanisme de control a optimizării accesului la date Deoarece de eficienţa optimizărilor depind critic performanţele globale ale SGBD, acestea oferă de cele mai multe ori administratorilor de bd posibilitatea controlului optimizărilor (“tuning”). De exemplu, dacă se constată că optimizatorul nu foloseşte niciodată (sau prea rar) un index s-ar putea hotărî ştergerea acelui index pentru a elibera spaţiu disc şi, mai ales, pentru a scurta timpul de decizie al optimizatorului; dual, dacă se constată că optimizatorul construieşte frecvent un index temporar, s-ar impune definirea sa cu titlu permanent. Pentru interogări al căror rezultat, ca urmare a selecţiilor, conţine doar puţini tuplii, unele SGBD îşi bazează calculul costurilor doar pe un eşantion restrâns de date, micşorând astfel cu mult timpul necesar fundamentării alegerii strategiei optime.
55
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Unele SGBD oferă chiar posibilitatea influenţării directe a comportării optimizatorului încorporat. De exemplu, prin modificarea sau adăugarea unor reguli de optimizare sau prin specificarea în interogări a unor indicaţii suplimentare de optimizare obligatorie a accesului într-un anumit mod (de exemplu, ignorând un index). Asemenea facilităţi extrem de puternice trebuie desigur folosite cu foarte mari precauţii: nu doar performanţele de moment ale sistemului pot avea de suferit (împiedicând chiar SGBD să mai poată evalua, de exemplu, interogări pentru care este obligat să folosească un indice care, între timp, a fost şters!), dar şi pe termen lung, căci asemenea tranzacţii pot inhiba şi versiuni ulterioare îmbunătăţite ale SGBD să optimizeze poate mult mai bine performanţele sistemului (până nu se renunţă la indicaţiile obligatorii). În general, optimizatoarele de azi sunt atât de evoluate, încât recursul la asemenea tehnici directe de control al optimizării este practic util doar în scop didactic.
Optimizarea globală a accesului în bd distribuite Optimizarea accesului în bd distribuite este, pe de-o parte, crucială (lipsa ei sau chiar slaba calitate a optimizării putând compromite total sistemul) iar pe de alta, extrem de dificilă. Cei mai importanţi factori ce trebuie avuţi în vedere sunt cardinalitatea structurilor de date (de exemplu, numărul de linii ale unei tabele şi dimensiunea liniei) şi costurile comunicaţiilor între servere. Aceasta se poate observa chiar şi analizând un simplu join, ca în exemplul 15.2: Exemplul 15.2
Fie trei servere distribuite la locaţiile A, B şi C; să considerăm o tabelă T cu 1.000 de linii memorată de A şi o alta, T’, cu 100.000 linii memorată de B; dacă se cere din C un join al T cu T’, această operaţie se poate, evident, executa conform multor strategii, dintre care cităm doar următoarele: 1. mută (copiază) ambele tabele în C şi efectuează join-ul la C; 2. mută (copiază) T’ în A, calculează join-ul în A şi mută rezultatul în C; 3. mută (copiază) T în B, calculează join-ul în B şi mută rezultatul în C. Desigur că, fie şi numai dpdv al cardinalităţii, decizia nu este uşoară: chiar dacă, evident, a doua soluţie poate fi eliminată ca fiind cea mai proastă întotdeauna, este greu de decis între prima şi a treia! Astfel, dacă rezultatul ar avea tot 100.000 linii, cele două soluţii sunt aproape la fel de costisitoare (prima probabil puţin mai ieftină, căci, în general, rezultatul unui join are mai multe coloane decât fiecare operand în parte); dacă el este mai mic, a treia variantă e preferabilă; dacă el este mai mare, prima variantă este preferabilă! Dacă însă se iau în calcul şi costurile transmisiei, lucrurile se complică şi mai mult, fiind posibilă răsturnarea clasamentelor de mai sus! Un bun optimizator însă va lua în considerare mulţi alţi factori, printre care: •
încărcarea curentă a serverelor participante;
•
performanţele platformelor de calcul implicate;
•
performanţele reţelelor implicate;
• eventualele constrângeri administrative (exemplu, în perioade de vârf a încărcării locale, administratorii bd locali pot restrânge accesul la distanţă); • constrângeri de spaţiu disc disponibil;
56
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 • alte costuri (de exemplu, dacă timpul de răspuns nu este critic şi dimpotrivă, tarifele de comunicaţie sunt mult mai avantajoase în anumite perioade de timp ale zilei, s-ar putea ca cea mai bună soluţie pentru exemplul de mai sus să fie a doua!). Toate aceste considerente, care implică mult mai multe meta-date non-locale decât locale, depăşesc cu mult capacităţile optimizatoarelor locale clasice şi impun considerarea unor optimizatoare globale, capabile să menţină statistici globale şi să acceseze statisticile oricărui server participant.
Comentarii şi referinţe bibliografice Optimizarea join-ului a fost în atenţia cercetătorilor încă din faza de proiectare a primului prototip de SGBD relaţional (System R al IBM), în 1976 [27] (deşi Gotlieb [159] a fost cel care, în 1975, a prezentat primele două metode de implementare a joinului). Autorii au proiectat, testat şi evaluat patru tipuri de soluţii, din care au reţinut doar pe cele ce s-au şi impus ulterior, într-adevăr, în toate SGBD comerciale: buclă în buclă şi sort/reuniune. În timp, au apărut diverse variante şi mici îmbunătăţiri ale acestora, din care multe sunt încă secrete, protejate “cu gelozie” de furnizorii de SGBD pentru păstrarea avantajelor faţă de concurenţă. Optimizarea evaluării expresiilor algebrice relaţionale, inclusiv euristica şi algoritmul prezentate în secţiunea 15.2, sunt descrise în amănunt de Ullman [336]; a doua ediţie [337] prezintă şi optimizarea exactă pentru interogările conjunctive, o submulţime a expresiilor SPJ.
Optimizarea în DB2 Optimizatorul DB2 al IBM, care a pornit de la prototipul System R, este considerat punctul forte al acestui SGBD. De exemplu, implementarea hibridă a joinului a fost proiectată pentru şi utilizată prima dată în DB2; în plus, el suportă “index AND” şi “index OR”, ca şi “buclă în buclă” şi “sort/reuniune”. Mai mult, pentru a-şi ajuta optimizatorul, DB2 calculează automat “închiderea tranzitivă a joinului”: de exemplu, pentru joinul exprimat în SQL prin: select from where and
* Ta, Tb, Tc Ta.C1 = Tb.C2 Tb.C2 = Tc.C3
and
Ta.C1 = Tc.C3
el adaugă automat: Utilizatorii care doresc să afle diversele variante avute în vedere de optimizator pentru evaluarea unei interogări, precum şi strategia aleasă în cele din urmă (fără ca interpretorul să şi evalueze interogarea, pentru a economisi timp!), pot invoca instrucţiunea EXPLAIN; efectul ei este doar memorarea datelor luate în calcul de optimizator, ca şi a rezultatului deciziei acestuia într-o tabelă PLAN_TABLE (al cărui conţinut, desigur, poate fi apoi interogat şi a cărui structură poate fi controlată şi ea de utilizator, prin eliminarea unor câmpuri în cazul în care nu toate detaliile interesează). Începând cu versiunea 3, DB2 permite utilizatorilor influenţarea optimizării prin clauza OPTIMIZE FOR n ROWS a instrucţiunii SELECT; aceasta furnizează optimizatorului informaţia că rezultatul interogării respective va avea maxim n linii (dacă, în realitate, ele vor fi mai multe, răspunsul va fi corect calculat totuşi, doar performanţele evaluării putând fi afectate). Pentru optimizarea în bd distribuite, DB2 oferă mai multe facilităţi, din care se disting evidenţierea în jurnale a activităţilor iniţiate la distanţă, mecanismele de citire şi transmisie a datelor în blocuri mari (până la 32 pagini cu o singură operaţie de I/O) şi execuţia SQL static (vezi capitolul 17) de la distanţă.
57
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Optimizarea în NonStop SQL NonStop SQL al Tandem, care permite programarea paralelă, foloseşte intens joinul “talmeşbalmeş” care, mai ales pe platforme ce oferă asistenţă hardware procesării paralele, se dovedeşte de foarte multe ori cea mai bună alegere în domeniu. Şi el utilizează toate celelalte metode de implementare a joinului, instrucţiunea EXPLAIN, precum şi furnizarea de informaţii utilizator suplimentare optimizatorului pentru a influenţa strategiile acestuia. Instrucţiunea CONTROL TABLE, de exemplu, poate chiar impune calea de acces dorită de utilizator (prin specificarea unui index obligatoriu). Citirea blocurilor mari de date cu o singură instrucţiune de I/O (aici referită ca “sequential block buffering”) permite accesul la 56K deodată; mai mult însă, operaţiile de I/O cu discul pot fi nu doar fizice, ci şi virtuale, pentru simplificarea sarcinii etajelor superioare ale SGBD: citirea fizică poate fi însoţită de selecţii, proiecţii şi agregări GROUP BY ale datelor, ce împing astfel aceşti operatori relaţionali chiar în frunzele arborilor de evaluare optimizată a interogărilor!
Optimizarea în Oracle Oracle mai suportă încă optimizarea bazată pe reguli, deşi s-a anunţat că următoarele versiuni vor renunţa la ea în favoarea optimizării exclusiv bazată pe costuri. Statisticile pot fi şi aici exacte sau aproximative; instrucţiunea EXPLAIN este şi ea oferită. Utilizatorii pot influenţa deciziile optimizatorului, nu doar indicând o cale de acces, ci chiar o anume implementare a joinului, sau scopul principal al optimizării (exemplu, viteza găsirii primelor linii sau a tuturor liniilor răspunsului). Oracle este capabil de “aplatizarea interogărilor”, adică de recunoaşterea subinterogărilor (SELECT în SELECT) ce exprimă, de fapt, joinuri şi de evaluarea lor ca atare (ceea ce este întodeauna mai ieftin!); cu mici excepţii însă, joinurile multitabele sunt evaluate în paşi implicând doar câte două tabele la un moment dat.
Optimizarea în SQL Server SQL Server al Sybase foloseşte doar “index OR” (nu şi “index AND”!) dar construieşte dinamic fişiere index temporare ori de câte ori acestea ar mări performanţele evaluării. Datele statistice despre fiecare index includ şi o pagină de distribuţie a valorilor cheii respective în tabelă, precum şi densitatea indexului (numărul mediu de duplicate). O altă particularitate remarcabilă este aşa-numita utilizare a “indexilor acoperitori” (“index covering”): dacă un index este definit pentru un produs de coloane, răspunsul la interogările ce implică doar coloane din cele ce alcătuiesc indexul este calculat doar pe baza fişierului index corespunzător, evitând şi consultarea tabelei indexate. SQL Server este şi el capabil de aplatizarea interogărilor; mai mult, el poate calcula joinuri multitabelă (implicând însă maxim 4 tabele; un join de şase tabele, de exemplu, va fi calculat totuşi în doar doi paşi în loc de cinci); din păcate însă el nu calculează automat închiderea tranzitivă a joinului, aceasta rămânând în sarcina utilizatorului. Joinul este implementat doar “buclă în buclă”!
Optimizarea în CA-OpenIngres Optimizatorul CA-OpenIngres se bazează tot pe date statistice (exacte sau aproximative) şi poate fi influenţat de utilizatori, care pot vizualiza planurile de optimizare şi strategiile de acces la date alese automat. Pentru datele cu distribuţie neuniformă, el poate menţine statistici pentru până la 250 valori distincte ale unei chei. Interogările distribuite sunt optimizate şi prin considerarea costurilor de transmisie şi a performanţelor procesor ale serverelor implicate. Joinul poate fi implementat şi “buclă în buclă” şi “sort/reuniune”; este implementată şi aplatizarea interogărilor.
58
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
8. CATALOAGE DE META-DATE Un catalog este un fişier sistem memorând meta-date (i.e. date despre datele memorate de bd). De exemplu, un catalog este necesar oricărui SGBD relaţional pentru a memora date despre tabelele oricărei bd gestionate: nume, sinonime, data ultimei modificări, dimensiuni etc. Alte cataloage sunt necesare pentru memorarea tuturor utilizatorilor autorizaţi ai fiecărei bd, precum şi a privilegiilor ce le sunt garantate. Cataloagele sunt automat create şi gestionate de SGBD, care are permanent nevoie să le consulte (de exemplu, pentru a determina dacă o tabelă există sau nu, dacă un utilizator este îndreptăţit la un anumit tip de acces într-o tabelă etc.). Optimizatoarele bazate pe costuri (vezi capitolul 15) au nevoie de memorarea şi ţinerea permanentă la zi a unor meta-date statistice suplimentare.
Structura şi conţinutul cataloagelor Structura cataloagelor diferă foarte mult de la un SGBD la altul, în funcţie de serviciile oferite de acestea (şi, desigur, de opţiunile proiectanţilor şi programatorilor care le-au realizat). În mod normal, şi ele ar trebui să constituie o bd sistem, structurată conform unui model oarecare al datelor, ca în SGBD relaţionale, unde cataloagele sunt memorate în zeci de tabele interconectate prin chei străine. Conţinutul cataloagelor este automat actualizat de sistem, obligatoriu şi transparent utilizatorilor, pentru fiecare actualizare a structurii unei bd (crearea sau ştergerea unei tabele, coloane, chei, fişier index, modificarea codomeniului unei coloane, structurii unei chei etc.), a privilegiilor garantate utilizatorilor autorizaţi etc. Unele meta-date ar putea însă fi actualizate manual, la comanda administratorului bd, pentru a mări performanţele sistemului (de exemplu: recalcularea datelor statistice necesare optimizatoarelor bazate pe costuri). Pe lângă meta-datele deja pomenite, cataloagele mai conţin informaţii despre constrângerile de integritate, punctele de vedere utilizator asupra datelor (“views”), trăgaciuri, tranzacţiile memorate, paginile disc de memorare a datelor, salvări, jurnale de actualizări, de verificare, de protecţie la viruşi etc. Unele SGBD distribuite menţin în plus meta-date despre serverele SGBD cu care sunt interconectate (nume, locaţie etc.).
Accesul utilizatorilor la cataloage Majoritatea SGBD moderne permit administratorilor bd accesul în citire la orice catalog şi chiar în scriere la o parte din acestea. Cum administratorul poate garanta orice privilegii celorlalţi utilizatori, oricine poate, la limită, avea acces la meta-date. Accesul în scriere este chiar obligatoriu pentru anumite meta-date, cum ar fi cele referitoare la autorizarea utilizatorilor şi privilegiile ce le sunt acordate. Accesul în citire este adesea cel mai important: doar cu ajutorul meta-datelor se poate realiza o bună administrare a bd, îmbunătăţirea performanţelor sistemului în condiţii locale şi/sau particulare de exploatare, ca şi o corectă şi optimă proiectare şi programare a bd (de exemplu, cea mai bună documentaţie despre structura unei tabele sau despre detaliile unui trăgaci rămâne cea memorată în cataloagele SGBD!). Desigur însă că, în esenţă, conţinutul cataloagelor este destinat a fi actualizat în special automat, transparent utilizatorilor. Chiar atunci când se permite scrierea de către utilizatori a metadatelor, SGBD preferă, ori de câte ori acest lucru este posibil, să interfaţeze cataloagele cu tranzacţii care să împiedice de fapt accesul direct în fişierele catalog, chiar dacă scrierea meta-datelor necesită privilegii speciale, tocmai datorită riscului foarte mare de a greşi (e omenesc!) cu consecinţe prea adesea incalculabile pentru integritatea bd gestionate.
59
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
Gestiunea cataloagelor în bd distribuite Un optimizator global ar avea nevoie de acces la toate cataloagele serverelor distribuite. O primă soluţie la acestă problemă a fost folosirea prefixării uzuale a numelor tabelelor cu locaţia serverului. Problema care rămâne însă este că toate serverele trebuie să fie omogene din acest punct de vedere, adică să aibă exact aceeaşi structură (inclusiv aceleaşi nume de tabele) pentru cataloagele gestionate. Cum azi un asemenea lucru este practic posibil de realizat doar foarte rar, datorită heterogenităţii serverelor, următoarea soluţie avută în vedere în bd distribuite a fost cea a menţinerii unui catalog universal, care conţine meta-date şi date statistice despre toate tabelele din gestiunea fiecărui server. Acesta permite oricărui SGBD distribuit să optimizeze accesul la date în orice moment, indiferent de distribuţia lor. Desigur că memorarea acestui catalog universal doar pe un singur server ar fi mult prea riscantă (în cazul căderilor de sistem sau izolării temporare a serverului implicat) şi neperformantă (căci ar încetini mult optimizatoarele celorlalte servere); de aceea, în implementările evoluate, el este replicat pe toate serverele. În sfârşit, un al treilea tip de soluţie exploatează avantajele transparenţei localizării: catalogul de la locul naşterii fiecărui obiect menţine date despre el până la ştergerea obiectului; cu condiţia omogenităţii cataloagelor sistemului, se pot obţine astfel meta-date şi statistici despre orice tabelă cu cel mult două accese la distanţă. Dezavantajul soluţiei (oricum inaplicabilă pentru cataloage heterogene) este însă acela că, în cazul inaccesibilităţii unui server implicat, datele de catalog despre obiectele “născute” la acea locaţie nu sunt temporar accesibile.
Comentarii şi referinţe bibliografice Din cauza diversităţii extreme care domneşte în această privinţă (practic, fiecare SGBD are structura sa proprie de cataloage precum şi politica sa de acces la ele) sunt greu de găsit prea multe texte teoretice dedicate acestui subiect; recomandăm totuşi [73]. Desigur că documentaţia fiecărui SGBD oferă detalii despre soluţia particulară aleasă în cazul respectiv. Am selectat, ca atare, pentru subsecţiunile ce urmează doar câteva particularităţi ce ni s-au părut interesante ale celor mai importante SGBD de pe piaţă. Ar merita amintit în acest context şi faptul că raportul tehnic [253] conţine proiectul cataloagelor SGBD prototip MatBase; acestea au fost gândite ca o bd a cărei schemă este proiectată cu ajutorul MMED (vezi prima parte a lucrării) ce fundamentează MatBase.
Cataloagele în DB2 DB2 al IBM, de exemplu, memorează şi statistici pentru optimizarea accesului în catalogul său unic (din mai multe tabele, dar pentru toate bd gestionate). Datele statistice menţinute pentru fiecare tabelă în parte includ: • • • •
numărul de linii; numărul de pagini (fizice disc alocate tabelei); fişierele index definite pe coloanele tabelei; pentru fiecare index (arbori B+): • adâncimea arborelui; • numărul de pagini frunză; • numărul de valori distincte ale cheii indexate;
60
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 • valorile maxime şi minime ale cheii, dar şi prima dintre valorile imediat sub, respectiv deasupra acestora (pentru a evita derapaje statistice atunci când se calculează numărul probabil de linii al tabelelor răspuns); • distribuţia valorilor pentru primele 10 valori apărând cel mai des în cheie.
Cataloagele în NonStop SQL NonStop SQL al Tandem menţine şi el câte un catalog (implementat prin mai multe tabele) pentru fiecare bd, nu neapărat pe acelaşi disc cu bd respectivă. Fiind un SGBD ce suportă mediile distribuite şi procesarea paralelă, fiecare nod menţine, în plus, un catalog rădăcină al nodului, ce conţine meta-date despre toate cataloagele gestionate de nodul respectiv. O interesantă particularitate este lipsa sintactică din limbaj a unei instrucţiuni de creare a unei noi bd; în schimb, există instrucţiunea de creare a unui catalog (care are drept efect secundar crearea unei bd corespunzătoare catalogului!). Clauza CATALOG a instrucţiunii de creare a unei tabele este singurul mod prin care se poate preciza apartenenţa tabelei la o bd. Meta-datele despre obiectele (tabele sau fişiere index) distribuite sunt replicate în catalogul corespunzător din fiecare nod implicat. Pentru menţinerea integrităţii datelor, s-a optat pentru o uşoară violare a autonomiei locale: crearea sau ştergerea unui obiect distribuit nu este admisă decât dacă toate nodurile implicate sunt disponibile în acel moment (i.e. în stare de funcţionare şi accesibile în reţea). Datele statistice sunt actualizate doar la cererea administratorilor de date; aceştia pot însă cere NonStopSQL să facă automat actualizarea la intervale regulate de timp. Statisticile pot fi exacte (i.e. luând în calcul toate datele implicate) sau aproximative (pentru care administratorul trebuie să precizeze numărul de blocuri de 4K ce vor fi luate în considerare).
Cataloagele în Oracle Oracle referă cataloagele drept dicţionare de date. Fiecare bd are propriul catalog, memorat într-un segment de încărcare (“bootstrap segment”) întotdeauna alocat în spaţiul de tabelă SYSTEM. Printre datele statistice suplimentare gestionate de Oracle se numără cele ce pot fi asociate fiecărei instrucţiuni SQL; acestea includ timp total şi timp procesor de execuţie, număr de linii procesate, numărul de accese logice şi fizice la disc etc.
Cataloagele în SQL Server SQL Server al Sybase are şi el cataloage separate pentru fiecare bd, memorate, la fel ca în Oracle, într-un segment al spaţiului de tabelă SYSTEM al bd respective. Bd MASTER a sistemului menţine, în plus, un catalog global, cu meta-date sistem, atât despre platforma de calcul (parametri de configurare, discuri, servere), cât şi despre bd gestionate (obiecte, dependenţe, privilegii etc.).
Cataloagele în CA-OpenIngres CA-OpenIngres al CA construieşte şi menţine câte un catalog (tot din mai multe tabele) pentru fiecare bd în parte. În plus, fiind un SGBD distribuit, el menţine şi un catalog global, inclusiv cu date statistice, care îi permite optimizarea interogărilor distribuite.
61
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
9. INTERFEŢE DE PROGRAMAREA APLICAŢIILOR (API) Orice SGBD oferă cel puţin o interfaţă de programare a aplicaţiilor (API), care să permită programatorilor să facă uz de serviciile SGBD dintr-un limbaj de programare. Astfel, atunci când un program scris într-un limbaj care beneficiază de un API are nevoie de acces la o bd gestionată de un SGBD corespunzător, el nu are nevoie nici să cunoască detaliile de memorare a datelor (care poate sunt memorate la distanţă, pe o platformă de un cu totul alt tip) şi nici să complice codul program cu foarte multe instrucţiuni suplimentare (stabilirea şi controlul derulării comunicaţiilor la distanţă, navigarea între tabele sau în tabele cu ajutorul indexurilor, sortare etc.). Şi din acest punct de vedere, însă, situaţia este complet diferită pentru SGBD orientate obiect: aşa cum am văzut (în capitolul 9) una din principalele caracteristici ale acestora este asigurarea doar a unei extensii pentru manipularea obiectelor persistente de către un limbaj de programare orientat obiect (sau cel mult două asemenea limbaje). Ca atare, deşi putem privi şi aceste extensii ca pe o API pentru limbajul respectiv, nu aceasta este uzanţa într-un domeniu în care se urmăreşte mai degrabă integrarea unui limbaj de programare existent în SGBD (acesta îndeplinind, ca atare, şi rolul de limbaj de definire şi manipulare a datelor). Prin urmare, restul consideraţiilor dezvoltate în acest capitol exclud SGBDO. Deşi sunt uzuale şi alte tipuri de limbaje de definire şi manipulare a datelor (precum QUEL, bazat pe calculul predicativ al tuplilor, sau QBE, bazat pe calculul predicativ al coloanelor) majoritatea SGBD oferă diverse variante de SQL (bazat pe algebra relaţională). Cum şi majoritatea implementărilor de QBE traduc intern în SQL, iar QUEL este foarte puţin răspândit, ne vom focaliza atenţia în acest capitol doar asupra SQL.
Interfeţe încorporate şi interfeţe apel Două tipuri de abordări ale API sunt comune în strategiile de a oferi acces la SQL din alte limbaje de programare: interfeţe cu SQL încorporat (“embedded SQL”) şi interfeţe de tip apeluri SQL (“call-level SQL”). Primul dintre ele este cel mai vechi, cel mai răspândit încă şi de nivel mai înalt decât al doilea. Acest prim tip de abordare permite includerea instrucţiunilor SQL în programe scrise întrun alt limbaj (“gazdă”), precedate şi terminate însă de diverse mecanisme sintactice de distingere a lor de restul liniilor de program scrise în limbajul gazdă. Dezavantajul acestei abordări este acela că sunt necesare precompilatoare care să traducă SQL pentru compilatorul de limbaj gazdă în apeluri la serviciile SGBD corespunzătoare. Deoarece acest pas suplimentar costă timp, SGBD mai noi oferă şi cel de-al doilea tip de API, care elimină necesitatea preprocesării: biblioteci de programare cu primitive ce admit drept parametrii instrucţiuni SQL. Şi această abordare, de tip apeluri SQL, are însă un mare dezavantaj, cel puţin deocamdată, deoarece, în absenţa oricărei standardizări în domeniu, programele ce fac apel la asemenea biblioteci (care diferă foarte mult între ele) nu sunt portabile.
SQL static şi dinamic. Proceduri memorate Optimizarea accesului la date este, după cum am mai văzut (capitolul 15), crucială în obţinerea unor performanţe bune ale SGBD, dar costisitoare în acelaşi timp. Pentru unele aplicaţii, a căror natură este ad-hoc dpdv al interogărilor (de exemplu, un program ce permite utilizatorilor în mod interactiv formularea oricărei întrebări), nu se poate face nimic pentru îmbunătăţirea performanţelor în acest sens. De aceea, majoritatea SGBD oferă doar SQL dinamic, adică optimizare a accesului la date la fiecare execuţie a oricărei tranzacţii SQL.
62
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008 Există însă şi multe aplicaţii de bd mereu previzibile şi care, în plus, trebuie reexecutate frecvent (exemplu: calculul şi listarea vânzărilor, salariilor, stocurilor, comenzilor etc.). Pentru a le mări viteza de execuţie, SGBD evoluate oferă şi SQL static, care memorează pe disc diversele variante posibile de acces la ele şi modul de calcul al strategiei optime pentru asemenea tranzacţii. Singurul dezavantaj major (dacă spaţiul disc suplimentar nu e o problemă) al acestei facilităţi este, evident, acela că tranzacţiile trebuie “recompilate” manual ori de câte ori apar sau dispar noi indexuri. O variantă intermediară între aceste două abordări, care elimină şi dezavantajul amintit imediat mai sus, o constituie facilitatea procedurilor memorate pe care o pun la dispoziţie câteva SGBD. Acestea nu memorează pe disc variantele de acces şi algoritmul de alegere a celei mai bune strategii pentru o tranzacţie (precum SQL static), dar, pentru procedurile memorate pe disc (în fond nişte subtranzacţii), păstrează în RAM aceste informaţii din momentul încărcării acestora în memorie şi până la momentul scoaterii lor din RAM. În tot acest răstimp, orice altă tranzacţie care face apel la asemenea proceduri (cu excepţia celei dintâi, evident), beneficiază de “precompilarea” optimizării accesului la datele implicate.
Comentarii şi referinţe bibliografice Nu am găsit în literatura de specialitate teoretică decât cel mult câte o subsecţiune dedicată API în general. Desigur că documentaţiile referitoare la diverse SGBD prezintă fiecare, explicit sau nu, API oferite de SGBD respectiv. Merită poate menţionat aici şi efortul firmei Borland, care încă de la versiunea Paradox 3.5, la sfârşitul anilor 80, a pus la dispoziţie atât biblioteci de apeluri (chiar dacă primitive, nu de SQL) pentru C şi Pascal (Paradox Engine), cât şi SQL Link, o interfaţă de acces la servere SQL. În ziua de azi, pe piaţa SGBD doar pentru PC-uri, este frecventă posibilitatea cuplării cel puţin la Microsoft SQL Server pentru Windows NT (server dezvoltat de Microsoft pornind de la licenţa SQL Server versiunea 4.2, achiziţionată de la Sybase). În paralel, se oferă de către orice produs care se respectă (exemplu: Access’95, ’97, Visual FoxPro, Paradox for Windows etc.) măcar acces la bibliotecile Windows API.
API în DB2 DB2 al IBM oferă API încorporat, cu SQL şi static şi dinamic, pentru foarte multe limbaje, incluzând COBOL, C, FORTRAN, PL/1, Assembler, Ada, APL2, Prolog şi IBM Basic. Versiunea 4 suportă şi proceduri memorate.
API în NonStop SQL NonStop SQL al Tandem oferă API încorporat pentru C, Pascal şi COBOL; un produs opţional al firmei, numit NonStop ODBC Server, furnizează o interfaţă de tip apeluri la NonStop SQL care suportă atât biblioteca Open Client (DB-Library) a Sybase, cât şi biblioteca Microsoft ODBC. SQL-ul său static, include numeroase facilităţi de compilare, dintre care cea mai spectaculoasă este evaluarea numelui obiectelor la momentul execuţiei: se pot scrie astfel tranzacţii “templet” ce pot fi apoi executate asupra mai multor tabele (eliminând deci munca de programare repetitivă) şi se pot uşor verifica tranzacţiile pe tabele de test.
API în Oracle Oracle oferă doar SQL încorporat dinamic şi Oracle Call Interface (OCI), o API de tip apeluri, pentru mai multe limbaje, incluzând C, COBOL, FORTRAN, Ada, PL/1 şi Pascal.
63
Facultatea de Matematică şi Informatică, Universitatea „Ovidius” Curs SGBD I – III, 2007 - 2008
API în SQL Server SQL Server al Sybase oferă API încorporat şi biblioteca de apeluri Open Client (DB-Library) pentru mai puţine limbaje, care includ totuşi Ada, C, COBOL şi FORTRAN. În plus însă, el oferă şi proceduri memorate.
API în CA-OpenIngres CA-OpenIngres, deşi construit în esenţă pe baza QUEL, suportă şi SQL, care poate fi dinamic încorporat în destul de multe limbaje, incluzând Ada, COBOL, C, FORTRAN, Pascal, PL/1 şi Basic. De asemenea, este suportată şi biblioteca Microsoft ODBC.
64