Migrácia z Oracle do PostgreSQL sa často plánuje ako prevod schémy. Nástroje na to existujú a tabuľky, indexy a väčšinu obmedzení preložia rýchlo. Práca, ktorá rozhoduje o termíne aj riziku, je inde: v dátových typoch, ktoré sa správajú inak, v uložených procedúrach, v SQL roztrúsenom po aplikáciách a v dôkaze, že dáta po prenose sedia. Článok je pre architektov, vedúcich vývoja a tých, ktorí migráciu schvaľujú alebo rozpočtujú.
V rokoch 2022 – 2023 sme migráciu dát z Oracle do PostgreSQL robili ako časť projektu optimalizácie štátnych informačných systémov, a to ako subdodávateľ cez partnerskú spoločnosť. Nižšie je päť miest, kde sme strávili najviac času, a postup, ktorý odporúčame. Technické tvrdenia vychádzajú z dokumentácie PostgreSQL a Oracle, správanie si však overte na svojich verziách.
Častým dôvodom migrácie sú licenčné náklady, keďže PostgreSQL sa šíri pod liberálnou open source licenciou PostgreSQL License. Úspora na licenciách však nie je celá bilancia: proti nej stojí práca na prevode a testoch, inak zabezpečená podpora a kompetencie tímu, ktorý doteraz poznal Oracle.
1. Dátové typy, ktoré vyzerajú rovnako
Prázdne reťazce boli u nás najdrahšia položka, lebo aplikácia s nimi počítala na desiatkach miest. Oracle podľa vlastnej dokumentácie považuje reťazec nulovej dĺžky za NULL (a odporúča sa na to nespoliehať), PostgreSQL ich rozlišuje. Aplikácia, ktorá zapíše prázdny reťazec, v PostgreSQL uloží skutočnú hodnotu: podmienka IS NULL ju nenájde, obmedzenie NOT NULL ju pustí a unikátny index pri druhom prázdnom reťazci nahlási konflikt. Rozdiel je aj pri spájaní: v Oracle spojenie reťazca s NULL vráti pôvodný reťazec, v PostgreSQL operátor || vráti NULL. Treba zvoliť jedno pravidlo, napríklad prázdny reťazec ukladať ako NULL, a uplatniť ho v dátach aj v kóde.
- NUMBER bez presnosti a mierky znamená v Oracle maximálny rozsah. Bezpečný preklad je numeric bez obmedzení, výpočty nad ním sú však podľa dokumentácie PostgreSQL výrazne pomalšie než nad celočíselnými typmi. Kde sú len celé čísla v rozsahu (kľúče, počty), patrí bigint. Rozhodnite podľa skutočných dát, nie podľa názvu stĺpca.
- DATE v Oracle obsahuje aj čas na sekundy, date v PostgreSQL čas nemá. Priamy preklad čas ticho zahodí, preto je cieľom spravidla timestamp. Navyše SYSDATE vracia aktuálny čas servera, kým now() v PostgreSQL čas začiatku transakcie.
- VARCHAR2 má dĺžku v bajtoch alebo znakoch podľa kvalifikátora BYTE či CHAR, bez neho podľa NLS_LENGTH_SEMANTICS. Varchar(n) v PostgreSQL počíta znaky, takže validácie dĺžky v aplikácii, ktoré počítali bajty, treba prejsť.
- CHAR dopĺňajú medzerami obe databázy, PostgreSQL však pri prevode na iný reťazcový typ koncové medzery odstráni a odporúča radšej text alebo varchar. Porovnania CHAR s VARCHAR otestujte.
- CLOB a BLOB sa prekladajú na text a bytea. Hodnota poľa má v PostgreSQL limit 1 GB, LOB v Oracle môže byť väčší. Vtedy treba large objects alebo úložisko mimo databázy.
- TIMESTAMP WITH TIME ZONE v Oracle uchováva pásmo alebo posun, timestamptz v PostgreSQL hodnotu prepočíta na UTC a pôvodné pásmo neuchová. Ak ho aplikácia potrebuje, patrí do samostatného stĺpca.
2. Sekvencie a identity
Sekvencie aj stĺpce identity sa dajú preniesť, ich hodnoty však treba nastaviť až po prenose dát. Funkcia setval nastaví poslednú vydanú hodnotu a nasledujúce nextval pokračuje za ňou. Pri stĺpcoch GENERATED … AS IDENTITY je pasca menej viditeľná: príkaz COPY podľa dokumentácie použije hodnoty zo vstupu bez ohľadu na nastavenie identity, takže pripojená sekvencia ostane na začiatku. Zabudnúť na to znamená konflikty primárnych kľúčov v prvý deň prevádzky. Nastavenie sekvencií preto patrí do skriptu prepnutia ako krok s kontrolou, nie medzi ručné úkony. Ak aplikácia vkladá vlastné hodnoty kľúča, variant GENERATED ALWAYS ich bez OVERRIDING SYSTEM VALUE odmietne.
3. Uložené procedúry
PL/SQL a PL/pgSQL sú si podobné na pohľad a rozdielne v detailoch. Automatický prevod dá kostru, zvyšok je ručná práca a testy:
- Balíky PostgreSQL nemá. Funkcie sa zoskupujú do schém a premenné balíka (stav relácie) treba nahradiť, napríklad dočasnými tabuľkami.
- Blok s EXCEPTION pri zachytení chyby vráti všetky zmeny od začiatku bloku, čo zodpovedá vzoru savepoint a ROLLBACK TO v Oracle. Je podľa dokumentácie výrazne drahší, preto nepatrí do tesných cyklov.
- Autonómne transakcie, typicky na audit či zápis chýb, PL/pgSQL nemá. Obchádzky cez rozšírenia (dblink, pg_background) otvárajú ďalšie spojenie. Často je čistejšie zapisovať taký log mimo databázovej transakcie.
- %TYPE a %ROWTYPE fungujú rovnako. BULK COLLECT a FORALL priamy ekvivalent nemajú. Väčšinou ich nahradí jeden množinový príkaz, nie cyklus po riadkoch.
- COMMIT a ROLLBACK sú od PostgreSQL 11 možné v procedúrach volaných cez CALL, nie však vo funkciách ani v bloku s EXCEPTION.
Rozšírenie orafce doplní časť funkcií a balíkov z Oracle (NVL, DECODE, tabuľku DUAL, DBMS_OUTPUT a ďalšie). Prevod urýchli, ale pridá komponent, ktorý treba udržiavať pri upgradoch a ktorý musí podporovať aj cieľové prostredie, napríklad spravovaná databáza v cloude. Procedúry, ktoré nikto nepoužíva, sa neprekladajú a migrácia je dobrá príležitosť zistiť, ktoré to sú.
4. Aplikácie s dialektom v kóde
Hľadanie Oracle dialektu v kóde aplikácií zabralo viac času ako databáza samotná. Pomohol zoznam vzorov a automatické vyhľadávanie, ale o každom mieste sa rozhodovalo ručne.
- ROWNUM nahradí LIMIT alebo FETCH FIRST. Oracle však ROWNUM vyhodnotí pred ORDER BY tej istej úrovne dotazu, takže pôvodný dotaz mohol vracať iné riadky, než autor zamýšľal. Mechanický prepis výsledok zmení, preto rozhodnite, ktorý je správny.
- NVL nahradí COALESCE, DECODE výraz CASE. DECODE považuje dva NULL za zhodné, CASE x WHEN NULL sa nezhoduje nikdy, preto treba IS NOT DISTINCT FROM.
- Spojenia cez (+) prepíšte na LEFT alebo RIGHT JOIN. Ak v Oracle (+) chýba v niektorej z viacerých podmienok, vráti sa bez varovania obyčajné spojenie, takže starý dotaz mohol mať skrytú chybu.
- CONNECT BY sa prepisuje na WITH RECURSIVE. LEVEL, cestu v strome a ochranu pred cyklami treba dopísať.
- MERGE PostgreSQL podporuje od verzie 15. Verzia 14 je podporovaná do 12. novembra 2026 a MERGE nemá. Náhrada INSERT … ON CONFLICT potrebuje unikátny index alebo obmedzenie a správa sa inak.
- Hinty v komentároch jadro PostgreSQL ignoruje. Výkon, ktorý na nich stál, overte plánmi dotazov na produkčnom objeme.
- Identifikátory bez úvodzoviek Oracle prevádza na veľké písmená, PostgreSQL na malé. Kód alebo ORM, ktoré mená dávajú do úvodzoviek veľkými písmenami, objekty nenájdu.
5. Transakcie, chyby a triedenie
Oracle má atomicitu na úrovni príkazu: ak príkaz zlyhá, napríklad na duplicitnom kľúči, vráti sa len on a predchádzajúca práca v transakcii ostane. V PostgreSQL chyba uvedie celú transakciu do zrušeného stavu a ďalšie príkazy sa odmietajú až do ROLLBACK alebo návratu na savepoint. Aplikácia, ktorá v Oracle zachytila chybu jedného INSERT-u a pokračovala, potrebuje savepoint pred rizikovým príkazom (napríklad ovládač JDBC ho vie vkladať automaticky, za cenu réžie) alebo inú logiku, napríklad INSERT … ON CONFLICT. Naopak, Oracle podľa dokumentácie najprv potvrdí rozpracovanú transakciu a až potom vykoná DDL príkaz ako samostatnú transakciu, ktorú tiež potvrdí. Ak DDL zlyhá, predchádzajúce zmeny ostávajú potvrdené. PostgreSQL podporuje transakčné DDL pri väčšine bežných zmien schémy, má však výnimky, napríklad CREATE DATABASE. Migračné skripty sa preto pri chybe uprostred správajú inak.
Pri texte rozhoduje kolácia. V Oracle sa ORDER BY riadi parametrom NLS_SORT a porovnania vo WHERE parametrom NLS_COMP, predvolene binárne. V PostgreSQL platí kolácia stĺpca alebo databázy pre triedenie aj porovnania. Výsledkom môže byť iné poradie pri diakritike a veľkých písmenách aj iné stránkovanie. Koláciu vyberte vedome pri vytváraní databázy.
Nástroje a overenie dát
Ora2Pg (open source, licencia GPL) preskúma databázu Oracle a vygeneruje skripty pre PostgreSQL vrátane procedúr, balíkov a exportu dát. Jeho správa s odhadom nákladov je dobrý vstup do plánu, nie rozpočet. Podobnú úlohu majú nástroje cloudových poskytovateľov, napríklad AWS. Žiadny z nich za vás nerozhodne, čo s prázdnymi reťazcami alebo s ROWNUM pred ORDER BY.
- Počty riadkov po tabuľkách sú minimum, nie dôkaz.
- Kontrolné súčty nad číselnými stĺpcami (súčet, minimum, maximum, počet NULL) a hashe nad textovými stĺpcami alebo vzorkami odhalia tiché chyby kódovania a presnosti. Hash musí vzniknúť z rovnako normalizovanej podoby na oboch stranách (formát dátumu, desatinná čiarka, NULL verzus prázdny reťazec), inak meria rozdiel formátov.
- Porovnanie riadok po riadku: Ora2Pg má režim TEST_DATA. Ak sa dáta medzitým menili, potrebuje primárny kľúč alebo unikátny index.
- Porovnanie výsledkov najčastejších aplikačných dotazov a reportov na oboch systémoch pred prepnutím, vrátane poradia riadkov, kde na ňom záleží.
Prepnutie a plán návratu
Prepnutie je samostatný scenár: zastavenie zápisov do Oracle, posledný prenos zmien, nastavenie sekvencií, overenie dát podľa vopred dohodnutých kritérií, testy aplikácie a rozhodnutie o spustení podľa merateľných kritérií, nie podľa pocitu. Osvedčuje sa celý scenár aspoň raz prejsť nanečisto na kópii produkčných dát so stopkami.
Plán návratu musí povedať, dokedy sa dá vrátiť a čo sa stane s dátami zapísanými už do PostgreSQL. Oracle po prepnutí nechajte nedotknutý a len na čítanie. Kým do PostgreSQL nikto nezapisuje, návrat je prepnutie spojení. Po prvých produkčných zápisoch znamená prenos zmien späť. Ten treba pripraviť a otestovať vopred, alebo vedome prijať, že od istého bodu sa ide len dopredu. Rozhodnúť to má vlastník systému pred prepnutím.
Kontrolný zoznam pred migráciou
- Inventár objektov a ich skutočného používania: čo nikto nevolá, sa nemigruje.
- Zoznam aplikácií, rozhraní, reportov a dávok, ktoré do databázy pristupujú.
- Zapísané a odsúhlasené pravidlo pre prázdne reťazce a NULL.
- Mapovanie typov stĺpec po stĺpci, overené na reálnych dátach.
- Kódovanie a kolácia cieľovej databázy.
- Cieľová verzia PostgreSQL s podporou počas plánovanej prevádzky (ak potrebujete MERGE, aspoň 15).
- Rozhodnutie o orafce a o tom, či ho cieľové prostredie podporuje.
- Skript nastavenia sekvencií ako súčasť prepnutia.
- Overovacie kritériá a referenčné dotazy s očakávanými výsledkami.
- Výkonnostné testy kľúčových dotazov na produkčnom objeme.
- Generálka prepnutia a plán návratu s bodom, za ktorým už nejde len o prepnutie spojení.
Migrácia sa podarila. Plán, ktorý počíta len s prevodom schémy, však podcení prácu niekoľkonásobne. Odporúčame začať inventárom a správou nástroja, pravidlá pre dátové typy rozhodnúť skôr, než sa začne prepisovať kód, a spôsob, ako dokážete, že dáta sedia, pripraviť pred prvým prenosom, nie po ňom.