- předchozí článek - následující článek - obsah - úvodní stránka -

Linuxové noviny 11/99

Transakce v databázových serverech (a co s těmi, které transakce nemají)

Jan Pazdziora, adelton@fi.muni.cz

Tento článek byl inspirován debatou v linuxové a databázové konferenci o tom, na co vlastně potřebujeme transakce. Obvláště dotaz pana Váchy "pokud mi systém nepadá, chybové stavy testuji, existuje případ, že danou úlohu bez transakcí neudělám?" nastolil zajímavý pohled na věc.

Podle manuálu Oraclu

Transakce je logická jednotka zpracování dat, která se skládá z jednoho nebo více SQL příkazů provedených jedním uživatelem.

Podstatné je, že transakce končí buď commitnutím, tedy promítnutím změn do databáze, nebo rollbackem, vrácením databáze do původního stavu, resp. neprovedením změn naakumulovaných v průběhu transakce. Cílem tedy je, aby byly ostatními paralelně pracujícími uživateli vidět buď všechny změny, nebo žádná.

Triviálním postupem je v okamžiku zahájení transakce jedním uživatelem zablokovat přístup pro ostatní, tedy databázi či její část zamknout, to ale není v multiuživatelském prostředí únosné. Databázový server tedy musí být schopen dát v jednom okamžiku různým uživatelům různé stavy databáze, protože jeden už něco změnil a druhý nikoli. Tito uživatelé se nesmějí navzájem nijak negativně ovlivňovat, práce jednoho nesmí blokovat práci druhého. Pouze pokud se oba pokusí změnit ta samá data (a záměrně neříkáme, zda ten samý řádek tabulky či tu samou tabulku, jelikož granularita se může server od serveru lišit), je zpracování jedné transakce pozastaveno do doby, než druhá transakce skončí.

Násobné kopie různých verzí databáze jsou uloženy ve zvláštních oblastech, nazývaných rollback segmenty či snapshoty. Zde jsou typicky uloženy původní stavy databáze, což zajišťuje, že commit je rychlý, neboť je pouze poznamenáno, že transakce již skončila a pro paralelně pracující uživatele již není nutno rekonstruovat původní verzi databáze. Rollback pak naopak znamená delší čas na navrácení původních dat na původní místo.

V nejstriktnějším módu izolace jednotlivých transakcí musí uživatel vidět v průběhu transakce databázi v takovém stavu, v jakém byla při zahájení transakce. Tedy ani paralelně běžící již commitnuté změny nesmí být viditelné. ASNI SQL standard zná i uvolněnější módy, například kdy transakce vidí nové řádky, které přidala (a commitnula) jiná, paralelní transakce.

Pokud databáze podporuje transakce, je možno toho s výhodou použít i pro rekonstrukci konzistentního stavu databáze po pádu, například při výpadku proudu - všechny necommitnuté transakce jsou zrušeny a databáze vrácena do původního stavu, kdy ani jedna z transakcí není neukončená.

Většina databázových serverů dovoluje uživateli přepnout se do tzv. autocommit nebo-li unchained módu, kdy je každý SQL příkaz implicitně okamžitě commitnut na disk. Typicky ale i zde se pro zajištění paralelní práce více uživatelů používá výše popsaného mechanismu, neboť i zpracování jediného SQL příkazu může trvat dlouho a tedy i takto krátkou transakci je vhodné pro zvýšení celkového výkonu serveru ošetřit vestavěným mechanismem správy násobných verzí dat než uzamčením celé tabulky či části databáze.

Pokud máme databázový server, který transakce nepodporuje, například MySQL či MiniSQL, co to pro naši práci znamená? Pokud chceme zajistit konzistentní pohled všech uživatelů na data, tedy nechceme, aby paralelně pracující uživatel viděl, že peníze již odešly z jednoho účtu, ale ještě nedorazily na druhý, musíme po dobu provádění takovýchto atomických akcí složených z více SQL příkazů relevantní tabulky zamknout a tím přístupu ostatních uživatelů k vnitřně nekonzistentním datům zabránit. Dále musíme psát aplikace tak, že nejprve ošetříme/otestujeme všechny chybové stavy, které mohou nastat (vložení duplicitní hodnoty do sloupce s primárním klíčem, porušená referenční integrita) a pak teprve začneme provádět akce, o kterých v podstatě předem musíme vědět, že budou úspěšné.

Nutnost zamykání tak paradoxně může vést k tomu, že systém je celkově méně průchodný než pokud by sám implementoval transakční zpracování. Je proto dobré zvážit, jakou třídu aplikací chceme na serveru provozovat. Pokud je databázový server nasazen v relativně jednoduché WWW aplikaci, kde většina přístupů je čtení dat a velmi malé procento změna malého objemu dat, či kde není množství paralelně pracujících uživatelů měnících data velké, je MySQL více než dostačující. Mimo jiné proto, že pro uchování násobných verzí databáze je nutno počítat s vyšší režií serveru i s dodatečným diskovým prostorem.

Naopak pro kritické aplikace je nutností databáze, která například pomocí redo logů a garantovaného zápisu bloků fyzicky na disk je schopna ošetřit i hardwarový výpadek, příkladem může být Oracle. Někde mezi pak stojí databázové servery typu PostgreSQL, kde transakce jsou vítaným nástrojem zjednodušení práce aplikačního programátora, který nemusí řešit množství případných chybových stavů a může psát aplikaci přímočařeji, kde případná chyba je pouze následovaná rollbackem bez potřeby dodatečných testů. Transakce mohou (ale nemusejí!) zvýšit průchodnost serveru zvláště při mnoha paralelních změnách, protože ve většině případů eliminují nutnost zamykání větších částí databáze než jednotlivých řádků.

Závěr a možná odpověď na otázku z úvodu? Ano, obejdete se bez transakcí. Pokud máte databázový server zvládnutý a vyhovuje vám a vaší aplikaci, asi není důvod přecházet na jiný jen kvůli magickému slůvku transakce. Pokud máte pod kontrolou všechny aplikace, které na data sahají, může být řešení My rychlejší a flexibilnější než řešení Ora. Na druhou stranu, nikdy nezaškodí vyzkoušet oboje a rozhodnout se dle vlastního pohledu. *


- předchozí článek - následující článek - obsah - úvodní stránka -