Výkonnost databázových aplikací III

1. 4. 1998

Sdílet

Rád bych navázal na poznámky z minulého čísla a věnoval se dalším fyzickým charakteristikám nebo, chcete-li, vl...





Rád bych navázal na poznámky z minulého čísla a věnoval se

dalším fyzickým charakteristikám nebo, chcete-li, vlastnostem

SŘBD, které přímo souvisejí s výkonností aplikací pracujících

nad daným SŘBD, resp. databází.



Řízení sdíleného přístupu



Mechanismy řízení sdíleného přístupu slouží pro realizaci

víceuživatelského prostředí databázových aplikací. Základním

problém je řešení paralelního přístupu více uživatelů k témže

řádkám určité databázové tabulky. Řízení sdíleného přístupu má

dva hlavní cíle:



- zabezpečení realizace transakcí, tj. mechanismu, kdy buď

všechny změny jedné transakce budou promítnuty do databáze, nebo

nebudou promítnuty do žádné



- zabezpečení vzájemné neovlivnitelnosti transakcí



Již z definice těchto cílů vyplývá, že základní pracovní

jednotkou zmíněných mechanismů jsou transakce. Provádění

transakcí má dva základní dopady:



- dopad na data prováděním příkazů INSERT, UPDATE, DELETE



- dopad na jiné transakce, pakliže tyto načetly data zapsané

danou transakcí



První z dopadů – přímý dopad na data lze eliminovat provedením

operace ROLLBACK s využitím záznamů v log souborech (viz minulá

část seriálu). Eliminace druhého dopadu na jiné transakce je

realizována databázovými zámky. Zámky jsou mechanismy

zabezpečující synchronizaci provádění transakcí v tom smyslu, že

lze jednu transakci ukončit příkazem ROLLBACK bez vlivu na

integritu jiných transakcí, které by jinak pracovaly s daty

vytvořenými nezakomitovanou transakcí.



Pakliže není zabezpečeno dostatečné řízení sdíleného přístupu

(zejména synchronizace transakcí), může to vést k řadě

problémům. Mezi nejčastější patří:



ignorace operace ROLLBACK – abych blíže popsal tento problém,

uvedu časově uspořádané zpracování dvou transakcí:







ztracené aktualizace: k tomuto problému dojde v okamžiku, kdy

dvě či více transakcí přistoupí ke stejným řádkám databáze a

provedou úspěšnou aktualizaci těchto řádek. V případě, že nejsou

k dispozici mechanismy zámků, mohou transakce přepsat poslední

modifikace, aniž se vůbec dozvědí, že k nějakým došlo.



problém nezakomitované závislosti: pokud jedna transakce provede

ROLLBACK, může to (opět v případě, že nejsou k dispozici

mechanismy zámků) způsobit ztrátu změn provedených jinou

transakcí. Problém lze vysvětlit na následujícím příkladu: řádka

je aktualizovaná jednou transakcí, ale tato aktualizace není

zakomitovaná. Poté je aktualizována i druhou transakcí, opět bez

provedení operace COMMIT. Pakliže následně první transakce

provede operaci ROLLBACK, dojde tak ke zrušení i aktualizačních

změn provedených druhou transakcí.



Zámky



SŘBD používají dva vzájemně se vylučující typy zámků: sdílené

zámky (shared locks, S-zámky) a exkluzívní zámky ( exclusive

locks, X-zámky). Dále je obvykle využíván jeden typ dočasných

zámků, tzv. update zámky (U-zámky). Jednotlivé SŘBD se liší

podle toho, na jaké úrovni zámky nastavují – zda na úrovni

databázových stránek či na úrovni jednotlivých řádek. Diskuse o

tom, který z těchto přístupů je lepší, není dosud uzavřena a dle

mého názoru nemá jednoznačný závěr.



Všechny zámky jsou nastavovány implicitně (tj. bez speciálního

požadavku transakce) SŘBD jako reakce na různé DML příkazy

transakce. Jedinou výjimkou je klauzule FOR UPDATE OF příkazu

SELECT, která způsobí explicitní nastavení U-zámku a předpokládá

následnou aktualizaci uzamčených řádek. Možnou koexistenci

jednotlivých typů zámků nad jedinou stránkou, resp. řádkou,

ukazuje následující tabulka:







Pro realizaci uzamykacích operací používají SŘBD protokoly

nazývané izolační úrovně . Tyto protokoly definují, jak dlouho

budou zámky nad danou stránkou, resp. řádkou, nastaveny a jakým

způsobem budou zpřístupňována data pomocí message bufferů.

Izolační úroveň volí transakce v okamžiku otevření prvního

kurzoru a zůstává v platnosti po celou dobu trvání transakce.

Izolační úroveň platí pro všechny kurzory používané transakcí.

Změna izolační úrovně uprostřed transakce způsobí vygenerování

implicitního COMMITu a spuštění nové transakce s novou úrovní

izolace.



Standard SQL-92 definuje následující izolační úrovně:



- serializable (S) – je to defaultní úroveň



- repeatable read (RR) – úroveň povoluje číst pouze komitované

záznamy a dále požaduje, že mezi dvěma čteními záznamu transakcí

nemá žádná další povoleno aktualizovat tato data. Nicméně

transakce nemusí být serializovaná vzhledem k ostatním

transakcím. Např. při hledání záznamů splňujících určité

podmínky může transakce nalézt některé záznamy vložené

komitovanou transakcí, ale nemusí nalézt jiné (dosud

nekomitované)



- read committed (RC) – Úroveň umožňuje číst jen komitované

záznamy, ale nevyžaduje repeatable reads. Např. mezi dvěma

operacemi čtení záznamu jednou transakcí může záznam

aktualizovat jiná komitovaná transakce



- read uncommitted (RU) – umožňuje číst i nezakomitované

záznamy. Je to nejnižší úroveň konzistence povolená standardem

SQL-92



Při návrhu víceuživatelských databázových aplikací je třeba

zvažovat dva protichůdné faktory ovlivňující výběr izolační

úrovně:



- konzistence dat



- sdílený přístup více uživatelů (potažmo i doba odezvy)



Vyšší stupeň konzistence dat je zpravidla zabezpečen na úkor

nižšího stupně sdíleného přístupu a tedy i delší doby odezvy

transakcí. Vztah jednotlivých protokolů k těmto dvěma kritickým

faktorům ukazuje následující schéma:







Indexování



Indexy jako vyhledávací technika nejsou nic nového. Nedávné

archeologické průzkumy dokonce naznačují, že v jisté podobě je

využíval již člověk neandrtálský. V oblasti výpočetní techniky

se zavedly jako prostředek pro snížení počtu diskových I/O

operací (a tedy zkrácení doby odezvy) a byly používány v

několika souborových systémech ještě před nástupem relačních

databází.



Primárním důvodem (ne však jediným) pro vytváření indexu je

zlepšení výkonnosti. Druhý důvod má co do činění s dosažením

unikátnosti mezi řádkami uloženými v databázové tabulce. Tabulky

v relační databázi jsou zpravidla navrženy s primárním klíčem.

Pakliže je do tabulky definované s primárním klíčem vložena nová

řádka, je na SŘBD, aby zajistil, že hodnota primárního klíče pro

tuto řádku je unikátní. V případě, že by SŘBD musela pokaždé,

když se vkládá nový řádek procházet celou tabulku, byla by

výkonnost velmi špatná. Vhodným řešením proto je vytvořit

unikátní index nad primárním klíčem a nechat jej, aby ho SŘBD

využívala jako donucovacího mechanismu pro zajištění unikátnosti

řádek.



Kdy vytvořit a kdy nevytvořit index



Zatímco je takřka povinností vytvořit unikátní index nad

primárním klíčem tabulky, existují i jiné situace, kdy je

použití indexu vhodné. Je ho možné např. využít nad cizím

klíčem. Jelikož je cizí klíč vždy joinován s primárním klíčem

druhé tabulky, bylo by sice možné pro urychlení operace join

využít unikátní index nad primárním klíčem druhé tabulky,

nicméně z důvodů výkonnosti a sdíleného přístupu je vhodné dát

SŘBD možnost použití indexu nad cizím klíčem, a to i v případě,

kdy již existuje index nad primárním klíčem v referenční

tabulce. V praxi se totiž hodnoty cizího klíče objevují jako

omezovací kritéria ve WHERE klauzuli, takže lze využít i

příslušný index.



Index by se dále měl použít i tehdy, když se některé sloupce

často vyskytují ve WHERE klauzuli, a to i v případě, že nejsou

součástí primárního ani cizího klíče. Čím více indexovaných

sloupců ve WHERE klauzuli je, tím více je i pravděpodobné, že

SŘBD bude schopná využít indexy pro zrychlení výkonnosti dotazu.



Existuje tu však i nevýhoda a jakési pravidlo: malý počet indexů

způsobuje pomalé zpracování dotazu, velký počet indexů na druhou

stranu způsobuje pomalé změny v databázi. To je cena, jakou je

třeba za indexy platit: zvýšený overhead, spojený s údržbou

indexů během provádění operací INSERT, UPDATE a DELETE. Cílem

tedy je najít „zlatou“ střední cestu mezi oběma extrémy.



Jednou z možností, jak toho dosáhnout, je vyjít ze situací, ve

kterých by se indexy vytvářet neměly.



V první řadě by se neměly vytvářet nad malými tabulkami. Pakliže

jen několik málo diskových operací čtení dokáže prohledat celou

tabulku, pak index vlastně zpomalí celé zpracování, jelikož

vyžaduje minimálně jeden až dvě operace čtení navíc. Co se ale

považuje za malou tabulku? Velikostní limit se liší v závislosti

na hardwaru, operačním systému, SŘBD a velikosti řádky, nicméně

každá tabulka s méně jak 100 řádkami je vhodným kandidátem.



Za druhé, indexy by se neměly vytvářet nad sloupci, které

nabývají jen několika málo hodnot (mají malý definiční obor).

Nejlepším kandidátem pro vytvoření indexu jsou sloupce s

unikátními hodnotami. Naopak sloupce, jež nabývají jen několika

málo hodnot (např. „pohlaví“) jsou kandidátem nejhorším. Pro

SŘBD je totiž daleko efektivnější v těchto případech projít

celou tabulku než použít index k nalezení 50 procent řádek.



Dále je třeba si uvědomit, že sloupce obsahující tzv. binary

large object (BLOB – také známé pod označením „long“ nebo „raw“

sloupce) nelze indexovat, a že pro to existuje velmi pádný

důvod. Index nad takovým sloupcem by zabral daleko více

diskového prostoru než samotná tabulka a výkonnost by se tudíž

značně snížila. Efektivní přístup k BLOB datům je předmětem

intenzivního výzkumu.



 

Autor článku