A PL/SQL programozási nyelv

Párhuzamosság

Bevezetés

Az valóban igaz, hogy szigorúan a PL/SQL nyelv nem bővelkedik párhuzamosságot támogató nyelvi elemekkel, még akkor sem, ha szintaxisát bevallottan az Ada-tól örökli. Azonban ez nem jelenti azt, hogy ne lehetne az adatbázis-motor által elvégzendő műveleteket párhuzamosítani, sőt.

Mint minden adatbáziskezelő, az Oracle is kifejezetten erős a szerver erőforrások optimalizálásában, a keresési műveletek erőforrásigényének előzetes becslésében, annak eldöntésében, mikor használjon indexet egy tábla átfésüléséhez és mikor ne, stb., majd ezen optimalizált és többségében előfordított műveletek minél magasabb párhuzamossági fokon (degree of parallelism) való végrehajtásában.

Sok esetben az adatbázis-kezelő implicit párhuzamosítást végez, anélkül, hogy a programozó bármilyen külön nyelvi elemmel erről nyilatkozna. Az Oracle adatbázis-kezelő képes párhuzamosítani a DML utasítások nagy részét (SELECT, INSERT, UPDATE, MERGE, DELETE), valamint néhány DDL műveletet, mint például indexek létrehozását, tábla létrehozását allekérdezésből, és az adatpartíciókon végzett műveleteket.

A műveletek párhuzamos végrehajtása végső soron több szerveroldali erőforrást, különösen pedig processzt ill. akár processzormagot is rendel az SQL utasítás végrehajtásához, amely így végeredményben sokkal rövidebb idő alatt hajtódhat végre, mint egyébként. Bizonyos előfeltételek teljesülése esetén nem ritka a teljesen lineárisan skálázható teljesítmény.

Végezetül érdemes megjegyezni, hogy az adatbázis-kezelő rendszerek tipikusan többfelhasználósak, azaz egyszerre sok felhasználó kéréseit szolgálják ki. Általában nem csak a felhasználók ad-hoc lekérdezéseit hajtják végre, hanem a programozók által előre megírt üzleti logika előfordított eljárásait futtatják, kérésre. Mindez a gyakorlatban azt jelenti, hogy az adatbázismotor akkor is párhuzamosan hajt végre programokat, amikor látszólag egyetlen bejelentkezett felhasználó egyetlen, szekvenciális lekérdezését hajtja végre. Hiszen jó eséllyel egy másik bejelentkezett felhasználó éppen ugyanezt a programot futtatja ugyanezeken az adatokon.

Oracle párhuzamos nyelvi elemek

Mint említettük, az Oracle implicit, azaz beépített, platformszintű szolgáltatásai működnek PL/SQL és SQL nyelvi elemek használatakor is anélkül, hogy speciálisan párhuzmaos nyelvi elemekkel párhuzamosságot kellene programoznunk.

Van azonban arra is lehetőség, hogy a programozó a párhuzamosság kezelését, elsősorban a párhuzamosság fokának meghatározását, saját kézbe vegye és explicite párhuzamos programot írjon PL/SQL-ben.

Megjegyzendő, hogy az implicit péárhuzamosságot kezelő szolgáltatások olyannyira fejlettek, hogy az általános ajánlás szerint a párhuzamosság kezelését jobb is rábízni az adatbázis-kezelőre, és csak kivételes esetekben indokolt ezeket felülbírálni és a programozónak saját kezébe vennie a párhuzamossággal kapcsolatos kérédéseket.

A legtöbb szolgáltatást e téren a DBMS_PARALLEL_EXECUTE csomag szolgáltatja, amely külön alfejezetet kapott, de vannak párhuzamosságot támogató eszközök e csomagon kívül is:

A továbbiakban ezeket a párhuzamos programozást támogató elemeket vesszük sorra, de nem feltétlenül pont ebben a sorrendben.

DBMS_JOB csomag használata

Történeti okokból ennek a csomagnak a rövid ismertetésével kezdjük a leírást. Azért csak röviden, mert ez csomag már elavult, és időközben leváltotta az újabb, DBMS_SCHEDULER csomag. Oracle szerint ajánlott a végrehajtási jogot (execution privilege) visszavonni erre a csomagra [7], miután a DBMS_SCHEDULER csomagra migráltuk [8] a csomag eljárásainak hívásait az alkalmazásunkban.

Fontos megjegyezni, hogy ha egy job-ot már sikeresen elindítottunk ezen a package-en keresztül, akkor egyáltalán nem egyszerű leállítani azt.

A csomag az alábbi, főbb szolgáltatásokat nyújtja:

A csomag részletesebb leírása, a fenti tárolt eljárások paraméterezése és példák a [7] linken érhető el, de még egyszer: a csomag használata az újabb Oracle kiadásokban már nem ajánlott, hanem helyette tanácsos a DBMS_SCHEDULER csomag használatára áttérni.

DBMS_SCHEDULER csomag használata

A DBMS_SCHEDULER csomag a DBMS_JOB csomagot váltja le. A migráció Oracle által ajánlott lépései a [8] linken találhatók. Rengeteg szolgáltatást nyújt nagyon sok tárolt eljárásban, nem is részletezzük itt mindet. Nem csak cron-szerűen, óra alapján lehet vele job-okat elindítani, hanem események (event-ek) is képesek elsütni a végrehajtandó tárolt eljárásokat. A tárolt eljárásokat láncokba (chain) tudja fűzni, nem csak egyenként tudja az eljárásokat indítani. A csomag segítségével időablakokat (window) lehet definiálni a SYS sémában, és az adott időablakhoz erőforrásprofilokat (resource plan) lehet rendelni. Az adott ablakban indított job-ok az előre adott erőforrásokhoz fognak hozzáférni.

A csomag az alábbi, főbb szolgáltatásokat nyújtja:

A csomag részletesebb leírása, a fenti tárolt eljárások paraméterezése és példák, valamint még több tárolt eljárás leírása a [9] linken érhető el.

DBMS_PARALLEL_EXECUTE csomag használata

A legtöbb szolgáltatást a párhuzamosság terén a DBMS_PARALLEL_EXECUTE csomag [10] szolgáltatja, igen sok hasznos beépített eljárással. Itt az alapötlet az, hogy a feldolgozandó adatsorokat nagyobb darabokra (chunk) osztjuk fel, kihasználva hogy a műveletünk elemenként feldolgozható, majd ezekre a chunk-okra indítjuk el több példányban, párhuzamosan a feldolgozó task-ot, amely task példányok futási eredményeit a végén összevezetjük, illetve commit-álunk, ha a művelet módosítja az adatokat. A chunk-okat képezhetjük Oracle fizikai sorazonosító (rowid), vagy felhasználó által definiált módon is. Ezekre példakód is található a már hivatkozott [10] linken, illetve szintén egy jó cikk még [11], szintén példakóddal és részletes kódmagyarázattal.

A csomag az alábbi, főbb szolgáltatásokat nyújtja (itt sem az összes tárolt eljárást soroljuk fel, csak a leglényegesebbeket, amelyek az alapötlet megértését segítik):

Lényeges megjegyzés, hogy a fenteb pontokba szedett eljárások a TASK_STATUS kivételével commit-ot is végrehajtanak, ezt tehát a tranzakcióhatárok tervezésénél figyelembe kell venni.

Egyéb párhuzamos nyelvi elemek

A fentebb bemutatott csomagokon kívül vannak még egyéb nyelvi elemek is a párhuzamosság programozó általi kézi vezérlésére. Ebben a szakaszban ezeket tekintjük át.

Ilyen nyelvi elemek a következők:

Ezeket most vázlatosan áttekintjük. A téma részletesebben a [12] linken van kifejtve, példakódokkal együtt.

Általános megjegyzések a műveletek párhuzamosíthatóságáról. Oracle azokat a műveleteket tudja hatékonyan párhuzamosítani, amelyek egy egész táblán vagy egy összefüggő partíción akarnának futni.

A párhuzamosítható műveletek általában:

Párhuzamos lekérdezések (Parallel Query)

Ez az egyik leggyakrabban használt párhuzamos Oracle szolgáltatás, valamint az egyik legrégebbi is: Oracle Parallel Query Option (PQO) néven már a 7.1-es Oracle-ben megjelent.

A lekérdezések párhuzamos végrehajtása jelentősen lerövidítheti a nagy lekérdezések futásidejét, de nem minden lekérdezés párhuzamosítható hatékonyan. Ahhoz az alábbi feltételeknek kell teljesülniük:

Ha a fentiek teljesülnek, akkor a lekérdezés párhuzamosítva fog végrehajtásra kerülni. A párhuzamosítás fokát (degree of parallelism) vagy automatikusan számolja ki Oracle a rendelkezésre álló erőforrás-adatok alapján, vagy pedig ezeket is explicite a programozó határozza meg, a parallel vagy parallel_index hint-ben. (Itt jegyezzük meg, hogy a noparallel és noparallel_index hint-ekkel lehet a párhuzamosítást explicite megtiltani, ha valamiért ez szükséges.)

Példa:

SELECT /*+ PARALLEL(emp,4) */ COUNT(*) FROM emp;

Parallel DML

Az Oracle adatmanipulációs (DML) utasításai (INSERT, UPDATE, DELETE) is jól párhuzamosíthatóak, nem csak a lekérdezések. Ezeknek inkább adattárház alkalmazásokban van jelentősége, ahol nagy mennyiségű historikus adatot kell megtartani, és ezeken valamilyen aggregációs műveletet végezni. Az OLTP rendszerekben nem annyira gyakori, hogy nagytömegű DML utasításokat kellene futtatni, de azért ott is előfordulhat, pl. a nap végi zárások batch futtatásai ilyenek lehetnek.

Mint a lekérdezések esetében, itt is speciális feltételeknek kell teljesülniük ahhoz, hogy a DML utasítás egyáltalán párhuzamosítható legyen. Érdekes, hogy az UPDATE és DELETE utasításoknak azonos feltételeik vannak, az INSERT-ekre azonban más feltételek kell teljesülniük.

Az UPDATE és DELETE DML utasítások pérhuzamosíthatók, ha:

Az INSERT utasítások párhumazosíthatóságának szabályai:

Példa:

insert /*+ parallel (emp_big,4,1) */ into emp_big select * from emp; commit;

Parallel DDL

Az adatdefiniáló (DDL) utasítások jól párhuzamosíthatók. Pontosabban: táblák és indexek létrehozása párhuzamosítható, függetlenül attól, hogy particionáltak-e vagy sem. Van viszont egy fontos feltétel: objektum ill. LOB típusú oszlopot tartalmazó táblán nem párhuzamosíthatók a DDL utasítások.

Nem particionált táblák és indexek esetében az alábbi DDL utasítások párhuzamosíthatók:

Particionált táblák és indexek esetében a lehetőségeink szélesebbek:

Példa:

CREATE INDEX emp_ix ON emp (emp_id) TABLESPACE ind STORAGE (INITIAL 1M NEXT 1M PCTINCREASE 0 MAXEXTENTS 20) PARALLEL (DEGREE 4);

Parallel Data Loading

Az Oracle SQL*Loader segédprogramja szolgál adatok külső forrásból, pl. szövegfile-okból adatbázisokba töltésére. Bizonyos feltételek teljessülése esetén ez a segédprogram képes a párhuzamos betöltésre, de ezzel sokkal több a kézimunka, mint rendesen, ugyanis a betöltendő file-okat kézzel kell kisebb darabokra tördelni, majd ezekre az inputfile-okra kell egyenként SQL*Loader session-öket indítani.

Parallel Recovery

Adatbázis visszaállításakor nagy vonalakban az történik, hogy az SMON háttérben futó processz elkezdi olvasni a redo log file-t, és az onnan olvasott tranzakciókat előregörgeti az adatbázison. Ez szerializált és rettentő hosszú művelet is lehet. Ezen lehet gyorsítani a parallel recovery segítségével. Itt az történik, hogy továbbra is az SMON olvassa a redo log file-t szekvenciálisan, de csak ez marad a feladata. Az adatbázis írására ugyanis több slave processz jön létre, akik az írási műveleteket párhuzamosan végzik az SMON koordinálásával. Így az is garantált marad, hogy az írási műveletek a megfelelő sorrendben hajtódnak végre.

Parallel Replication

Az Oracle replikációs szolgáltatásaival elérhető, hogy ugyanannak az adatbázis-objektumnak több adatbázisban is legyen egy-egy másolata. Ezt az SNP (snapshot) háttérben futó processz intézi. Ha nagyon nagy mennyiségű adatot kell replikálni, az átviteli sebesség megnövelhető a párhuzamos propagálással.

Párhuzamos propagálás esetén az történik, hogy egynél több slave processz jön létre és ennek megfelelően egynél több adatkapcsolat a slave adatbázis felé. Ezáltal több, pérhuzamos adatfolyam (data stream) jön létre, és ezeken keresztül folyik a replikáció.

Mint a visszállításnál, itt sem mindegy a tranzakciók sorrendje. Oracle tudja garantálni azt, hogy az egymástól függő tranzakciók ugyanabba a stream-be kerüljenek, tehát ugyanaz a slave processz olvassa őket. Ezt a system change number (SCN) segítségével tudja megtenni.

A párhuzamos replikációt az adatbázis link objektum szintjén lehet beállítani.

Utasításszinten meghatározott párhuzamossági fok

Mint a fentebbi példékban látható volt, a párhuzamosság fokát magában az SQL utasításban is elő lehet írni, például a parallel hint használatával, vagy a parallel clause használatával. Ilyen esetekben beszélünk utasításszinten meghatározott párhuzamossági fokról.

Adatobjektum szinten meghatározott párhuzamossági fok

Lehetőség van azonban már az adatbázis objektum létrehozásakor rendelkezni arról, hogy az adott objektumon jól párhuzamosíthatók a műveletek. Ilyenkor a tábla, index, vagy egyéb objektum CREATE DDL utasításában, vagy már létrehozása uán, ALTER utasítással az Oracle adatszótárban rögzítjük a párhuzamossággal kapcsolatos elképzeléseinket. Ilyen esetekben beszélünk adatobjektum szinten meghatározott párhuzamossági fokról.

Összefoglaló

Az Oracle adatbázis-kezelő adatmotorja és a PL/SQL nyelv lehetőséget biztosít a programozó által, nyelvi elemekkel kódolt explicit párhuzamos programozásra is, ha ez feltétlenül szükséges. Ezeket kivonatosan áttekintettük a fentiekben.

Lényeges megjegyzés azonban, hogy az Oracle adatbázis-kezelő adatmotorjának fejlett optimalizációs képességei és az adatszótárról (data dictionary) vezetett rengeteg metrika, indexek, stb. lehetővé teszik az adatbázis-kezelő számára az erős párhuzamos optimalizációt akkor is, amikor erről a programozó explicite nem rendelkezik.

Hivatkozások

[1] Oracle Corporation: Oracle Database Parallel Execution Fundamentals. An Oracle whitepaper. October 2010.

[2] Oracle Corporation: Oracle Database VLDB and Partitioning Guide 11g Release 2 (11.2). E25523-01. September 2011. Chapter 8: Using Parallel Execution, pp. 209-277.

[3] Oracle Corporation: Oracle Database Data Warehousing Guide 10g Release 2 (10.2). B14223-02 Chapter 25: Using Parallel Execution

[4] Oracle Corporation: Oracle9i Database Concepts, Release 2 (9.2). Part Number A96524-01. Chapter 18: Parallel Execution of SQL Statements

[5] Using Oracle's Parallel Execution Features.

[6] Using parallel SQL to improve Oracle database performance.

[7] DBMS_JOB package description.

[8] Moving from DBMS_JOB to DBMS_SCHEDULER

[9] DBMS_SCHEDULER package description

[10] DBMS_PARALLEL_EXECUTE package description

[11] TECHNOLOGY: PL/SQL Practices. Steven Feuerstein: On Working in Parallel

[12] Using Oracle's Parallel Execution Features