2007. december 3., hétfő

Architektúra part #3 – Tranzakciókezelés

A tranzakció legalább egy SQL utasítást magába foglaló műveletsorozatot jelent. Elemi műveletként értelmezzük, ami annyit tesz, hogy a tranzakciót alkotó SQL utasítások mindegyike végrehajtódik (commitálódik), vagy egyik sem (roll back – visszagörgetés). Egy tranzakció jóváhagyása vagy visszagörgetése explicit módon a COMMIT vagy ROLLBACK utasításokkal, implicit módon az alkalmazásból való kilépéssel vagy egy DDL utasítás végrehajtásával történhet.
Utasítás szintű visszagörgetésről akkor beszélünk, ha egy SQL utasítás valamilyen hiba folytán nem tud lefutni. Ilyen hiba lehet például, ha már létező elsődleges kulcsot akarunk létrehozni, ha két SQL utasítás között versenyhelyzet áll elő, vagy egyszerűen csak szintaktikailag nem helyes az utasítás. A hibás utasítás nem okozza az egész tranzakció visszagörgetését, pusztán csak a saját feladatát nem tudja végrehajtani.

Nagy adatbázis műveletek számára előnyös lehet, hogyha egy tranzakció helyfoglalási problémák következtében nem tud tovább futni, akkor nem visszagörgetés következik, hanem lehetősége van az adatbázis adminisztrátornak a hibát elhárítania, majd a tranzakciók zökkenőmentesen futhatnak tovább. (Resumable space allocation)

Egy tranzakció futásának kezdetén a visszagörgetéshez szükséges információk tárolására hozzárendelünk a tranzakcióhoz egy undo tablespacet. A tranzakció végén a következők állhatnak elő:
  • a felhasználó COMMIT vagy ROLLBACK utasítást ad ki.

  • a felhasználó valamilyen DDL utasítást (CREATE, DROP, RENAME vagy ALTER) ad ki. Ebben az esetben az adatbázis először commitálja a tranzakciót, majd csak azután hajtja végre a DDL utasítást, mint egy egy utasításból álló külön tranzakciót.

  • a felhasználó kapcsolatot bont az adatbázissal. Ekkor automatikusan commit hajtódik végre.

  • a felhasználói processz abnormálisan áll le. Ekkor automatikusan rollback hajtódik végre.


Commitálni egy tranzakciót annyit tesz, mint véglegesíteni az adatbázisban az SQL utasítások által végzett műveleteket. A commit előtt az adatbázis a következő műveleteket hajtja végre: undo információkat generál, melyek a az SQL utasítások által módosított adatok módosítás előtti változatát tárolják. Illetve az SGA redo log bufferjébe redo log bejegyzéseket tesz, melyek az adatblokkokon illetve roll back blokkokon történt változásokat rögzítik. Előrefordulhat, hogy ezek az adatok a tranzakció commitálását megelőzően már a lemezre kerülnek. A commit után a következők mennek végbe:
  1. az undo tablespacehez tartozó belső tranzakciós táblában feljegyezzük, hogy a tranzakciót commitálták, s beírjuk a tranzakció egyedi SCN (system change number) számát.

  2. az SGA redo log bufferjének redo log fájljába bejegyzéseket tesz az LGWR (log writer process), s szintén beírja a tranzakció SCN számát, ami egyben a tranzakció commitálását is jelenti.

  3. az adatbázis elengedi a tranzakció által használt zárakat.

  4. a tranzakciót késznek jelöli.


Egy tranzakció visszagörgetése (roll back) annyit jelent, hogy egy lezáratlan tranzakció minden addigi adatmódosítását visszaállítjuk az adatok eredeti értékére. A régi adatokat az undo tablespaceben, a változtatásokat a redo logban tároljuk. Lehetőség van savepointok definiálására, amikkel egy nagyobb tranzakciót kisebb részegységekre bonthatunk, így ha valahol hiba történik, akkor a visszagörgetés nem teljesen a tranzakció elejéig történik, hanem a legutolsó savepointig (már ha volt addig). A visszagörgetés a következő lépésekből áll:
  1. az adatbázis az undo tablespace alapján minden addigi, a tranzakció SQL utasításai által végrehajtott módosítást visszacsinál. Savepoint esetén természetesen csak az adott savepointig kell visszacsinálni mindent, vagyis csak a savepoint után szereplő SQL utasítások által módosított adatokat kell a régi értékükre visszaállítani.

  2. Ha volt savepointunk, akkor azt az adott savepointot természetesen megőrizzük, de minden utána megállapított savepointot törlünk.

  3. Elengedjük a tranzakció zárjait. Természetesen ha savepointot alkalmaztunk, akkor itt is csak a savepoint után igényelt zárakat engedjük el. Azok az adatok, melyek a savepoint előtt már zárolva voltak, természetesen továbbra is zárolva maradnak.


Kétfázisú commit működési elve:
Egy elosztott adatbázisban hálózati vagy rendszer hibák esetén is gondoskodni kell a hálózat feletti tranzakcióvezérlésről és az adatok konzisztenciájáról. Elosztott tranzakciónak nevezünk egy tranzakciót, ha tartalmaz legalább egy olyan utasítást, ami módosít legalább két különböző hálózati végpontokon lévő adatbázisokat. A kétfázisú elv biztosítja, hogy elosztott tranzakció minden adatbázisa konzisztens marad, vagyis az összes adatbázis vagy commitálja a tranzakciót, vagy visszagörgeti annak addigi hatásait.

Léteznek ún. autonóm tranzakciók, melyeket más tranzakciók hívnak meg, de azoktól teljesen függetlenül futnak le. A hívást követően a meghívó tranzakció felfüggesztődik, a meghívott tranzakció teljesen független zárakkal és utasításokkal lefut, majd függetlenül attól, hogy committáltunk vagy visszagörgettük a tranzakciót, folytatódik a meghívó tranzakció futása. Ezáltal természetesen létre lehet hozni holtpontot, amit az adatbázis hibaüzenettel ugyan jelez, de ezekért a holtpontokért teljes mértékben az alkalmazás fejlesztője felel. Egy autonóm tranzakció is meghívhat más autonóm tranzakciókat, nincs semmilyen korlát a hívások mélységére. Lehetőség van azonban nem autonóm tranzakciók meghívására is. Ekkor a meghívott tranzació örökli a hívó tranzakció környezetét.


Kapcsolódó link:
Oracle® Database Concepts: Transaction Management

Architektúra part #2 – Táblaterek és Adatfájlok

A logikai adattárolás legnagyobb egységei a tablespacek, míg a fizikai tárolás datafileok formájában történik. Az Oracle adatbázis tartalmaz legalább két tablespacet, a SYSTEM-t és a SYSAUX-t, illetőleg egy harmadik, TEMP nevű tablespacet opcionálisan. A tablespacek adatait fizikailag egy vagy több datafile tárolja. A fájlrendszer további részeit képezik még a visszagörgetéshez használt Redo log fájlok, illetve az adatbázis indításához és működéséhez elengedhetetlen Control fájlok. Az adatbázisunk méretét háromféleképpen növelhetjük:

  • új tablespacet hozunk létre

  • egy már létező tablespacehez új datafilet adunk hozzá

  • egy már létező datafile méretet növeljük (engedélyezhetjük, hogy az adatbázis ezt dinamikus hajtsa végre, amint szüksége van több területre)


A tablespacek, ahogyan azt már tárgyaltuk, szegmensekből épülnek fel, melyeket extentek alkotnak, amiket pedig összefüggő adatblokkok képeznek.

A 64-bites rendszerek képességeinek kiaknázása érdekében lehetőség van ún. „bigfile tablespace”-k létrehozására. Ez lényegében annyit jelent, hogy az adott tablespaceünket mindössze egyetlen datafile alkotja, így a szokványos „smallfile tablespace”-kkel szemben jóval nagyobb datafilet használthatunk – egészen pontosan mivel a smallfile tablespacek maximum 1024 datafilet tartalmazhatnak, ezért a bigfile tablespaceünk egyetlen datafileja akár 1024szer lehet nagyobb. A datafilek számára is van egy felső korlát (64K), ezért mivel a bigfile tablespacek tablespacenként csak egy datafilet tartalmaznak, lehetőségünk van hatalmas adatbázisok tárolására egészen 8 exabyte (10^18) méretig, illetve a kevesebb datafile miatt könnyebben kezelhető lesz az adatbázisunk. Cserébe viszont a bigfile tablespacek (néhány kivételtől eltekintve) csak lokálisan vezérelt (locally managed), automatikus szegmens-foglalási tablespaceként működhetnek.

A SYSTEM táblaspace automatikusan létrejön, amikor az adatbázist létrehozzuk. Alapvetően könyvtár vezérelt (dictionary managed), de természetesen ezt átállíthatjuk lokális vezérlésre is, azonban ezáltal a későbbiekben nem tudunk könyvtár vezérelt tablespaceket létrehozni, s a létezőket is csak olvasni tudjuk. A SYSTEM tablespaceben tároljuk a data dictionary táblákat, illetve a tárolt PL/SQL eljárásokat.
A SYSAUX tablespace a SYSTEM-t kiegészítő tablespace. Sok adatbázis komponens használja alapértelmezett tárolási helyként, illetve az összes, nem a SYSTEM tablespaceben lévő metaadatot itt tároljuk.
Az UNDO tablespacek csak és kizárólag undo infomárciókat tartalmaznak, s csak automatikus undo menedzselt módban (alapértelmezett) alkalmazhatóak. Lehet ugyan több ilyen tablespaceünk, azonban használatban egyszerre csak egy lehet. Az undo tablespacek automatikusan létrejönnek, mindig lokálisan vezéreltek, s néhány ritkán előforduló körülménytől eltekintve a tranzakciókat első DML eljáráshívásuk után hozzárendeljük egy undo szegmenshez.
Ha a SYSTEM tablespaceünket lokális vezérlésre állítottuk, mindenképpen definiálnunk az ideiglenes adatok tárolására egy ideiglenes tablespacet, de ajánlott könyvtár vezérelt módban sem a SYSTEM-be szemetelni. A könnyebb kezelhetőség és a versenyhelyzet elkerülése érdekében természetesen ajánlott a felhasználók adatainak számára is külön tablespace(ke)t létrehozni.

A tablespacek területének menedzselésére kétféle mód kínálkozik:

  1. A lokálisan vezérelt tablespacek egy bitmapben tartják számon a datafileban használt és szabad területeket. Előnyük, hogy ezáltal nem kell foglalkozni a szomszédos szabad területek összeolvasztásával, illetve nincs szükség rekurzív területvezérlési műveletekre (pl. ha felszabadítunk helyet egy extentben, akkor az nem idéz elő semmilyen más műveletet a data dictionaryben vagy rollback szegmensben). A SEGMENT SPACE MANAGENT paraméterrel beállíthatjuk, hogy AUTO (alapértelmezett) vagy MANUAL módban szeretnénk-e kezelni a szegmensen belüli területeket. Előbbi esetben az adatbázis a bitmap alapján automatikusan kezeli a szabad területeket, míg utóbbiban egy (az előző részben már említett) free list-ben tartjuk nyilván az olyan adatblokkokat, ahova van lehetőség új sor beillesztésére.

  2. A könyvtár vezérelt mód az Oracle 9i verziójától elérhető. Ebben az esetben bitmapek helyett az adatbázis a SYSTEM tablespacen belül kezel egy data dictionaryt, melyet minden extentfoglalás és –felszabadítás esetén frissít, s ezekről a frissítésekről a rollback szegmensekben tárol információt.


Lehetőség van a SYSTEM tablespace kivételével (mivel annak data dictionaryjére mindig szüksége van egy futó adatbázisnak) bármely tablespacet online módból offline módba átállítani. Erre karbantartáskor vagy biztonsági mentés létrehozásakor lehet szükség, de bizonyos hibák esetén az adatbázis automatikusan is offline módba állíthat egy tablespacet. Ilyenkor természetesen semmilyen olyan SQL utasítás nem hajtható végre, ami az adott tablespacen belüli objektumokra hivatkozik.

Biztonsági okokból adott tablespaceket lehet csak olvasásra (read-only) is engedélyezni.

A CREATE TEMPORARY TABLESPACE utasítással ideiglenes tárolási célokra használt tablespaceket hozhatunk létre. Ezek nagyban növelhetik a rendezést használó utasítások végrehajtásának hatékonyságát. Természetesen egy temporary tablespace nem használható állandó sémaobjektumok tárolására.

Lehetőség van tablespaceink adatbázisok közti szállítására is. Ehhez nyújt segítséget a tablespace repository, amelyben a tablespacek egy halmazának szállításához szükséges fájlokat tároljuk. Nem árt ügyelni arra, hogyha egy könyvtár vezérelt tablespacet költöztetünk át egy lokálisan vezérelt SYSTEM tablespaceszel rendelkező adatbázisba, akkor azt ott csak olvasni tudjuk majd, írni nem.

Egy tablespacet ugyebár fizikailag datafile(ok) alkotnak. Egy datafile csak egy tablespacehez és adatbázishoz tartozhat. Létrehozásakor az általa kijelölt terület formatálódik, s az adatbázis lefoglalja a későbbiekben szükséges extentek létrehozására. Az ideiglenes táblahelyek ideiglenes datafilejai kevesebb tulajdonsággal bírnak szokványos társaiknál: például nem logolnak és nem lehet őket read-only módra állítani.

Az adatbázis indításához és működéséhez az ún. control fileokat használja. Ezeknek mindig írásra alkalmasnak kell lenniük, hisz az adatbázis működés közben folyamatosan frissíti bennük a fizikai architektúra és a visszagörgetéshez szükséges redo logok leírását. Ebből kifolyólag ha a control fileok nem elérhetőek vagy sérülnek, az adatbázis nem fog helyesen működni, ezért erősen ajánlott több azonos control filet egyszerre, különböző fizikai lemezeken tárolni és frissíteni.


Kapcsolódó link:
Oracle® Database Concepts: Tablespaces, Datafiles, and Control Files

2007. november 21., szerda

Architektúra part #1 – Logikai struktúra

Az Oracle Database logikai felépítése alapvetően három szintből áll. A legkisebb egységet az adatblokkok (data blocks) képezik, amik egy előre meghatározott, fix pár bytenyi részt jelentenek. A fizikailag folytonosan elhelyezkedő, valamilyen tárolási célból előre lefoglalt adatblokkok képezik a következő szintet, az extenteket. Ha egy extent betelik, de szükség van további szabad helyre, akkor új extentet kell foglalnunk. Az így keletkező, azonos célra foglalt, s azonos táblahelyen (tablespace) elhelyezkedő extentek alkotják a harmadik hierarchia szintet, a szegmenseket (segments).

Az adatblokkok méretét a DB_BLOCK_SIZE kezdeti paraméter beállításával adhatjuk meg, egy bizonyos felső korláttal, hogy elkerüljük a nagy adatblokkokból származó felesleges I/O-műveleteket.
Az adatblokkra vonatkozó információkat tartalmazó overheadet (header, table directory, row directory) leszámítva használt és szabad területekre oszthatjuk a felhasználás szempontjából lényeges helyet. Használatban lévő területet felszabadítani nyilvánvalóan két utasítás fog: a DELETE és az olyan UPDATE, ami az addigi értéket egy kevesebb helyet foglalóra módosítja. Az így keletkező területek nem feltétlen fognak folytonosan elhelyezkedni, azonban mivel ezek az utasítások viszonylag gyakran előfordulhatnak, a töredezettség csökkentését csak akkor végzi el az Oracle Database, ha egy INSERT vagy UPDATE művelet olyan blokkot akar használni, ahol van elég hely számára, azonban nincs a blokkban olyan összefüggő hely, ami elég lenne számára.
Fontos még megemlíteni, hogyha egy tábla sorának az adatai nem férnek bele egy adatblokkba, akkor azt adatblokkok láncolásával illetve pointerekkel ugyan megoldja az adatbázis, de az ebből fakadó többszörös I/O műveletek csökkentik a teljesítményt.
Manuálisan felügyelt tablespaceknél két paramétert használhatunk az adatblokkok szabad területéhez történő hozzáférés vezérlésére:
A PCTFREE-vel beállíthatjuk, hogy az adatblokk hány százalékát akarjuk update-ekre fenntartani. Azaz ha az adatblokkban felhasznált terület eléri a (100-PCTFREE)%-t, akkor kiszedjük az adatblokkot ’free list’-ből (az a lista, amely tartalmazza, hogy mely adatblokkoknál alkalmazhatjuk az insert műveletet).
A PCTUSED paraméter egy minimum értéket ad a használt területre, amíg nem kezdeményezhetünk új instertet. Azaz ha a felhasznált terület az itt megadott érték alá esik, akkor az adatblokk visszakerül a ’free list’-be, s ismét lehet új sorokat is ide beilleszteni.

Az extentek néhány folytonosan elhelyezkedő adatblokkot jelentenek, melyek lefoglalása egyidejűleg és előre történik. Például egy tábla létrehozásakor automatikusan lefoglal neki az Oracle Database egy kezdeti extentet, majd ha ez a terület kevésnek bizonyul, akkor további, legalább a kezdeti extent méretével egyező, vagy annál nagyobb extenteket. Ehhez a datafile-ok bitmapjeit használja, amik alapján megállapítható, hogy hol van megfelelő mennyiségű szomszédos szabad blokk.
Az extentek felszabadítása alapesetben csak akkor történik meg, ha töröljük az adott táblát. Kivételt képeznek ez alól a manuális műveletek, illetve a rollback szegmens, aminek méretét az Oracle Database periódikusan optimalizálja.

Azok az extentek, melyek egy tablespacen belül logikailag összetartozó struktúrát képeznek, alkotnak egy szegmenset. Például egy táblához vagy indexhez tartozó extentek jelentik az adott táblához illetve indexhez tartozó szegmenset.
A hatékonyság szempontjából fontos tárolási paramétereket mind a táblák, mind az indexek létrehozásakor illetve módosításukkor beállíthatjuk. Egy indexnek azonban nem feltétlen kell az általa hivatkozott táblával egy tablespaceben lennie… így a tárolási paraméterek beállításánál akár egy másik tablespacet is választhatunk.
Léteznek még az ún. ideiglenes szegmensek is, melyeket az Oracle Database automatikusan lefoglal, ha valamely művelet végrehajtása során szüksége van a memóriát meghaladó területekre, vagy ha egy tranzakció során ideiglenes táblá(ka)t használunk. Az ideiglenes szegmensek tárolására használt tablespaceket a felhasználók létrehozásánál illetve módosításánál a TEMPORARY TABLESPACE paraméterrel állíthatjuk be. Ez alapesetben a SYSTEM tablespacet jelenti, azonban ajánlott legalább egy ilyen tablespacet létrehozni, hogy elkerüljük a SYSTEM nagymértékű tördelődését.
Fontos még megjegyezni, hogy a 9i verziótól ugyan már automatikusan működik a tranzakciók visszagörgetése – amivel egy inkonzisztens állapotból térhetünk vissza egy konzisztensbe -, azonban egy rosszul működő tranzakció túlságosan nagy részét foglalhatja el az visszagörgetéshez használt undo tablespacenek. Ezért lehetőség van a felhasználók egy bizonyos csoportjának, vagy akár egy adott felhasználónak is közvetlen korlátozni az undo területét. Erre szolgál az UNDO_POOL paraméter, melynek default értéke természetesen UNLIMITED. Így ha egy csoport egy felhasználója megtölti a csoport számára kijelölt területet, akkor nem hajthat végre további update-eket mindaddig, amíg egy másik csoportbéli felhasználó tranzakciója be nem fejeződik, s ezáltal területek szabadulnak fel.


Kapcsolódó link:
Oracle® Database Concepts: Data Blocks, Extents, and Segments

2007. október 11., csütörtök

Az Oracle optimalizáló eszközei

Az Enterprise Linux 5, illetve az Oracle 11g telepítése néhány gigabyte memória-bővítést követően egy-két kisebb akadály lekűzdése után végül zökkenőmentesen végbement.
Majd következett az Oracle két legfontosabb optimalizáló eszközével való ismerkedés.

A Diagnostic Pack legfontosabb része az ADDM (Automatic Database Diagnostic Monitor), amely a teljesítményproblémák automatikus diagnosztizálását végzi. Egy problémaelemzési fát bejárva gyorsan és hatékonyan keresi a működés szűk keresztmetszeteit, illetve azoknak konkrét okait. Ehhez nyújt segítséget az Automatic Workload Repository (AWR), amely folyamatosan gyűjti és tárolja az adatokat az adatbázis működéséről és terheléséről.

A Tuning Pack az SQL-kódok automatikus optimalizálását teszi lehetővé. Ehhez az SQL Tuning Advisor négyfajta elemzést végez (Statisztikai elemzés, SQL Profiling, Elérési utak elemzése, SQL-struktúra elemzés), majd optimalizálási javaslatokat tesz a várható előnyök ismertetése mellett. Az ehhez szükséges adatokat különböző forrásokból képes egy SQL Tuning Set objektumba fogadni.
A Tuning Pack másik fontos része az SQL Access Advisor, amely az adatbázis-séma optimalizálását segíti indexek és nézetek létrehozására/elhagyására történõ tanácsokkal.
A Tuning Pack harmadik komponenseként tartalmazza az Object Reorganization Wizardot, amely objektumok átszervezésével, táblaterek hatékony helykihasználásával segíti elő a teljesítménynövekedést.

A későbbiekben ezekhez keresek példákat, hogy a működésüket közelebbről is megismerhessem/kipróbálhassam (ehhez természetesen tanácsokat is szívesen fogadok), illetve az optimalizálási eljárásokat tanulmányozom (CBO vs RBO).

2007. október 4., csütörtök

Kezdet

A blog elsődleges célja, hogy önálló labor konzulenseim (Kardkovács Zsolt (BME) és Sárecz Lajos (Oracle)) bármikor on-line nyomon követhessék az előrehaladásomat. Emellett természetesen a blogot bárki olvashatja, így remélhetőleg a későbbiekben egyesek számára hasznos forrásként is funkcionál majd.

Előreláthatólag a következő napok folyamán az Oracle 11g felépítésével ismerkedem majd, illetve tanulmányozom a relációs adatbázisokban végezhető optimalizálási eljárásokat. A későbbiekben szakirodalmak feldolgozását végzem elsősorban, s próbalom elsajátítani többek között a hintek megadásának módját, valamint különböző példaprogramokat és teszteket vizsgálok és hasonlítok majd össze.