====== Konkurencia és adatkonzisztencia ====== ===== Alapfogalmak ===== * SQL-utasítás: * **DDL-utasítás**: ''CREATE'', ''ALTER'' * **DML-utasítás**: ''INSERT'', ''UPDATE'', ''DELETE'' * **lekérdezés**: ''SELECT'', ''SELECT ... FOR UPDATE'' (lekérdezés zárolással) * **tranzakció**: egységként kezelt SQL-utasítások, melyek vagy mindegyike teljesül (''COMMIT'') vagy egyike sem teljesül (''ROLLBACK'') * **erőforrás**: (itt) felhasználói objektum (pl. tábla, sor) vagy rendszerobjektum (pl. adatstruktúra az osztott memóriában, adatszótár stb.) * **zár**: olyan mechanizmus, amely megakadályozza, hogy a tranzakciók egy időben (konkurensen) ugyanahhoz az erőforráshoz hozzáférjenek * adathozzáférés típusai: * **írás/módosítás**: összes DML-utasítás; kizárólagos (//exclusive//) zárat igényel * **olvasás**: lekérdezés; osztott (//shared//) zárral egyszerre több tranzakció is olvashat (de egyik sem módosíthat, hiszen ehhez kizárólagos zár kellene) * **zárkonverzió**: a táblán lévő zár típusának automatikus megváltoztatása, szigorítása írást követően: ''RS'' -> ''RX'' * **deadlock** (halálos ölelés): egymást blokkoló tranzakciók, egymás által zárolt erőforrásra várnak * **automatikus zárolás**: az Oracle automatikusan a megfelelő zárat alkalmazza minden SQL-utasításhoz * **manuális zárolás**: zárolás kikényszerítése SQL-utasításokkal (''SELECT ... FOR UPDATE'', ''LOCK TABLE ...'') * **többverziós konkurenciakezelés**: azon adatok régi értéke, amelyet egy nem kommitált vagy nemrég kommitált tranzakció megváltoztatott, az **//UNDO// táblatérben** tárolódik konzisztens nézetek biztosításához (UNDO mechanizmus) ===== Izolációs szintek ===== * az SQL-92 szabvány négy tranzakció izolációs szintet definiál, ebből kettő van az Oracle-ben (plusz egy nem szabványos): - **//read committed// izolációs szint** (csak kommitált adatok olvashatók) - **//serializable// izolációs szint** (sorosított tranzakciók) - //read-only// izolációs szint (az adatok olvashatók, de nem írhatók) * három hatás, amely felléphet konkurens tranzakciók esetén: - **dirty read**: egy tranzakció olyan adatot olvas, amelyet egy másik tranzakció írt, de még **nem kommitált** - **non-repeatable (fuzzy) read**: egy tranzakció újraolvas egy adatot, és annak más az értéke, mint az előző olvasáskor, mert közben egy másik, kommitált tranzakció **módosította vagy törölte** azt - **phantom read**: egy tranzakció újrafuttat egy lekérdezést, amelynek eredménye eltér a lekérdezés egy korábbi eredményhalmazától, mert közben egy másik, kommitált tranzakció **új sort szúrt be** Az izolációs szinteket a fenti három hatás függvényében definiálja a szabvány: | ^ dirty olvasás ^ fuzzy olvasás ^ fantom olvasás ^ ^//read committed// | nincs | lehet | lehet | ^//serializable// |nincs|nincs |nincs | ==== Read committed izolációs szint==== * alapértelmezett szint * **utasításszintű olvasási konzisztencia**: minden olyan adat, amelyet egy lekérdezés olvashat, az adatbázis egy adott időpontbeli állapotát tükrözi (konzisztens nézet) * ezt **az Oracle mindig garantálja** (UNDO mechanizmus segítségével) * az utasítás ideje alatt más utasítás hatása nem érvényesül * nem küszöböli ki a fantom és a nem megismételhető olvasások veszélyét (sokszor nem is elvárás, ill. ritkán beérkező tranzakciók esetén kicsi ez a veszély) * nagyobb konkurenciát biztosít, mint a sorosított tranzakciók, így nagyobb throughput és rövidebb válaszidő érhető el ==== Serializable izolációs szint ==== * **tranzakciószintű olvasási konzisztencia:** olvasási konzisztencia egy tranzakció összes lekérdezéséhez, azaz egy tranzakción belül minden lekérdezés az adatbázis egy adott időpontbeli állapotát látja (konzisztens nézet, UNDO mechanizmus) * a tranzakció ideje alatt más tranzakciók hatása nem érvényesül * véd a nem megismételhető és fantom olvasások ellen * ha a tranzakció olyan sort akar módosítani, amelyet egy konkurens tranzakció közben módosított és kommitált, akkor az **''ORA-08177: can't serialize access for this transaction''** hiba keletkezik * egy olvasó/író tranzakció több lekérdezést futtathat konzisztensen * magasabb konzisztencia szint, de kisebb konkurenciát biztosít * nagy adatbázisokhoz; ahol kevés sort módosítanak/két tranzakció kis eséllyel módosítja ugyanazt a sort/rövid tranzakciók vannak (vagy a hosszú tranzakciók csak olvasnak) ===== DML- és DDL-zárak ===== ==== Zártípusok ==== === Sorzár (TX) === * DML-utasítások igénylik * egy tábla ugyanazon sorát két tranzakció egyidőben nem módosíthatja (mindig kizárólagos zár) * egy tranzakció csak akkor módosíthat egy sort, ha azt a sort zárolta * egy tranzakció bármennyi sorszintű zárat tarthat fent * a többverziós konkurenciának (UNDO mechanizmus) köszönhetően: * egy sort olvasó tranzakciónak nem kell várnia egy másik tranzakcióra, amely ugyanazt a sort írja * egy sort író tranzakciónak nem kel várnia egy másik tranzakcióra, amely ugyanazt a sort olvassa (kivéve: ''SELECT ... FOR UPDATE'') * a sorszintű zárolásnak köszönhetően: * egy író tranzakciónak csak akkor kell várnia egy másik író tranzakcióra, ha mindkettő egyidejűleg ugyanazt a sort akarja írni * egy sor zárolása egy táblában automatikusan maga után vonja a tábla zárolását is === Táblazár (TM) === * táblán végzett DDL- és DML-utasítások igénylik * DML-műveletekhez automatikusan: DML-hozzáférés korlátozása, DDL-műveletek kizárása DML-művelet ideje alatt * nem befolyásolja a DML-utasítások konkurenciáját * particionált táblák esetén partíciónkénti zárolás ==== Táblazárolási módok ==== Néhány módnak két neve van: a "row" (sor) és a "sub" (rész) itt szinonimák. Magyarázat: a tábla egy összetett objektum, és annak "rész"-e a "sor". A táblákra tehető zárak szigorúsági sorrendben: === Row share (RS) / subshare table (SS) === * **módosítási szándék**: a tranzakció sorokat zárolt és írni akar a táblába (''SELECT ... FOR UPDATE'') * más tranzakció módosíthat még nem zárolt sorokat a táblában * legkevésbé szigorú (legnagyobb adatkonkurenciát tesz lehetővé) * manuálisan: ''LOCK TABLE ... IN ROW SHARE MODE'' === Row exclusive (RX) / subexclusive table (SX) === * **módosítás történt**: a tranzakció egy vagy több sort írt a táblába (''INSERT'', ''UPDATE'', ''DELETE'') * más tranzakció módosíthat a már módosított soroktól eltérő sorokat a táblában * manuálisan: ''LOCK TABLE ... IN ROW EXCLUSIVE MODE'' === Share (S) === * **táblaszintű konzisztencia: más tranzakció nem módosíthatja a táblát** * más tranzakció olvashat és ''SELECT ... FOR UPDATE'' utasítással zárolhat módosítandó sorokat a táblában * **a tranzakció csak akkor módosíthatja a táblát, ha más tranzakció nem zárolja ''S'' módban** * csak manuálisan: ''LOCK TABLE ... IN SHARE MODE'' === Share row exclusive (SRX) / share-subexclusive table (SSX) === * **ugyanolyan mint az ''S'', de egyszerre egy tranzakció zárolhatja a táblát ebben a módban** * csak manuálisan: ''LOCK TABLE ... IN SHARE ROW EXCLUSIVE MODE'' === Exclusive (X) === * **egy tranzakció kizárólagos hozzáférése a táblához módosításra** * más tranzakció csak olvashat a táblából, ''SELECT ... FOR UPDATE'' //nem// megengedett * legszigorúbb * csak manuálisan: ''LOCK TABLE ... IN EXCLUSIVE MODE'' ==== Táblazárak alkalmazása ==== * **az Oracle mindig automatikusan zárol** (''RS'', ''RX'' táblazárak), ezzel biztosítja az utasításszintű olvasási konzisztenciát * **az Oracle mindig a lehető legkevésbé szigorú zárat alkalmazza **, a konkurencia maximalizálása érdekében * az ''S'', ''SRX'', ''X'' táblazárak csak manuálisan igényelhetők * **a zárolás módja meghatározza, hogy más tranzakció milyen módon zárolhatja ugyanazt a táblát:** | ^ Igényelhető ^^^^^ ^ Jelenlegi ^ RS ^ RX ^ S ^ SRX ^ X ^ ^ RS | ✔ | ✔ | ✔ | ✔ | ✘ | ^ RX | ✔ | ✔ | ✘ | ✘ | ✘ | ^ S | ✔ | ✘ | ✔ | ✘ | ✘ | ^ SRX | ✔ | ✘ | ✘ | ✘ | ✘ | ^ X | ✘ | ✘ | ✘ | ✘ | ✘ | Részletesebben: [[http://docs.oracle.com/cd/B28359_01/server.111/b28318/consist.htm#BABCJIAJ|Summary of table locks]] === Manuális zárolás === * a zárolási automatizmus felülbírálható: * **manuális zárolás**: ''LOCK TABLE ...'', ''SELECT ... FOR UPDATE'' * **izolációs szint átállítása**: * tranzakciós szinten: ''SET TRANSACTION ISOLATION LEVEL [READ COMMITTED | SERIALIZABLE]'' * session szinten: ''ALTER SESSION SET ISOLATION_LEVEL = [READ COMMITTED | SERIALIZABLE]'' === Alkalmazásoldali szempontok === * az Oracle-ben **sorszintű zárolás** van: egy tranzakció mindenképpen várni kényszerül, ha olyan sort akar módosítani, amelyet egy konkurens tranzakció módosított, de még nem kommitált * az Oracle-ben az **olvasások és írások nem blokkolják egymást** (kivéve ''SELECT ... FOR UPDATE'' esetében, amely lekérdezés és RS módú zárolás is egyben) * **az izolációs szint megválasztása kompromisszum a konzisztencia és a konkurencia között** * egy tranzakció által írt adatot később felülírhat egy másik tranzakció, így nem feltételezhető, hogy egy tranzakcióban elolvasott adat változatlan marad a tranzakció következő futásáig: **az egymást követő tranzakciók közötti konzisztenciát ellenőrizni kell az alkalmazásban**, sorosított (//serializable//) tranzakciók esetén is * a //serializable// szint több fejlesztői munkát igényel: a ''can't serialize access'' adatbázishiba figyelése és a tranzakció újraindítása/visszavonása szükséges * ha az alkalmazás maga ellenőrzi a sorosíthatóságot, akkor használható a //read committed// szint, amely nem dob sorosítási hibát ==== DDL-zár ==== * egy DDL-utasítás futása közben azon objektumok definícióját védi, amelyekre az utasítás hivatkozik * az adatszótár megfelelő része automatikusan zárolódik a DDL-zár igénylésekor * manuálisan nem igényelhető * DDL-utasítások esetén implicit commit van === Kizárólagos === * majdnem minden DDL-utasítás ilyen zárat igényel, a DDL-utasítások egymást kizárják === Megosztott === * egyidőben futtatható DDL-utasítások, melyek megosztott zárat igényelnek: * ''CREATE [OR REPLACE] VIEW/ PROCEDURE/PACKAGE/PACKAGE BODY/FUNCTION/ TRIGGER'' * ''CREATE TABLE'' (kivéve ''CLUSTER'' esetén) * ''CREATE SYNONYM'' * ''AUDIT'', ''NOAUDIT'' * ''COMMENT'' * pl. ''CREATE PROCEDURE'': a hivatkozott objektumok megosztottan zárolhatók több CREATE utasítás által, de egyik sem igényelhet kizárólagos zárat === Feltörhető parse-olási zár === * az SQL-utasítások (vagy PL/SQL programegységek) a shared pool-ban ún. parse-olási "zárat" tartanak fenn minden hivatkozott sémaobjektumra * ha a hivatkozott objektum megváltozik vagy eldobják, akkor az SQL-terület érvénytelenné válik a záron keresztül * a DDL-utasításokat nem tiltja, konkurens DDL-utasítások ellen nem véd (feltörhető) ===== Rendszerszintű zárak ===== === Latch === * alacsony szintű sorosító mechanizmus az SGA-ban lévő osztott adatstruktúrák védelmére * szerver és háttérfolyamatok igénylik nagyon rövid időre, amíg ezekkel az adatstruktúrákkal dolgoznak * megvalósításuk OS-függő, főként a várakozási időt tekintve === Belső zár === * belső adatbázisstruktúrákat (pl. adatfájlok) véd * magasabb szintű, bonyolultabb mechanizmus, mint a latch === Adatszótár cache zár === * nagyon rövid idejű zár a adatszótár cache-elt bejegyzésén * inkonzisztens objektumdefiníciók elkerülésére * módok: * **shared**: a parse-olás végéig * **exclusive**: DDL-művelet végéig === Fájl- és logkezelő zár === * fájlokat véd * hosszú idejű === Táblatér és rollback szegmens zárak === * több adabázispéldány egyidejű hozzáférést tiltja a táblatérhez