Optimalizace dotazů SQL v INFORMIXU

 

* Optimalizující techniky

* Porozumění celému systému

* Porozumění aplikaci

* Měření aplikací

* Nalezení vinných funkcí

* Optimizér

* Důležitost pořadí tabulek

* Jak optimalizér pracuje

* Čtení plánu

* Časová cena dotazu

* Aktivity v paměti

* Řízení diskového přístupu

* Cena čtení řádky

* Cena sekvenčního přístupu

* Cena nesekvenčního přístupu

* Cena přístupu podle ID

* Cena indexového přístupu

* Nízká cena malých tabulek

* Cena síťového přístupu

* Rychlé dotazy

* Příprava testovacího prostředí

* Studium schématu

* Studium Dotazového plánu

* Modifikace dotazu

* Užití dočasných tabulek k urychlení dotazů

 

 

 

  Jak dlouho bude trvat vyhodnocení vašeho dotazu? Kolik diskových operací během jeho zpracování bude potřebovat? Pro mnoho dotazů nezáleží, o kolik je uděláte rychleji než člověk, ale musí být provedeny v určitém limitu časovém nebo co zvládne váš stroj. Tento referát by měl být o zlepšování vašich dotazů. To předpokládá, že máte danou pevnou strukturu tabulek a nemůžete ji měnit.

 

Měl bych pokrýt následující témata:

-Obecná diskuse technik pro optimalizaci SW zdůrazňující všechny věci před zásahem do SQL výrazu

-Popis optimizéru, části rozhodující, jak bude daný dotaz proveden. Když víte, jak pracuje, můžete tvořit lepší dotazy.

-Diskuse o rychlostech operací

-Souhrn technik, které by vám měly pomoci zlepšit vaše dotazy.

 

 

Optimalizující techniky *obsah

 

Před tím, než začnete optimalizovat svoje SQL dotazy, je důležité udělat krok zpět a vidět je jako část většího systému skládajícího se z následujících částí:

-Jeden nebo více programů

Uložené dotazy, zkompilované obrazovkové formuláře a reporty a programy v jednom nebo více jazycích, v kterých je SQL vestavěno.

-Jeden nebo víc počítačů

Přinejmenším jeden počítač, kde jsou uloženy programy a databáze.

-Jeden nebo více správců

Lidé zodpovědní za programy.

-Jeden nebo více uživatelů

-Jeden nebo více organizací

 

Můžete pracovat ve velké organizaci, kde je každá tato část oddělená, nebo si to můžete dělat vše sami na malém počítači.

V každém případě je důležité rozlišovat dva body o systému jako celku.

1) cíl systému je sloužit uživateli.

2) SQL výrazy tvoří pouze malou část systému, často se nejefektivnější zásahy do systému týkají jiné části.

 

 Následující část je obecný postup pro analýzu problému výkonnosti. Smysl postupu je ukázat možná, i netechnická, řešení.


 

Porozumění celému systému

 

Uvažujte celý systém. Řešení může být ve změně plánování nebo řízení zdrojů 


 

Porozumění aplikaci

 

Naučte se vše o porozumění aplikaci jako celku. Databázová aplikace má obvykle mnoho částí- uložené dotazy,obrazovkové formuláře, reporty, programy. Uvažujte je dohromady a ptejte se:

-Jak to funguje (Odhaluje zbytečné činnosti, zda každý krok akce je důležitý.)

-Proč to funguje (Zvláště ve starých aplikacích jsou nejasné kroky.)

-Pro koho to pracuje (Ujistěte se, že každý výstup někdo potřebuje a jestli mu nestačí jednodušší formát)

-Jaké části zdržují


Měření aplikace

 

Nemůžete dělat významné pokroky v problému, pokud ho nezměříte. Musíte najít způsob jak opakovaně změřit pomalé části aplikace. Důvody jsou takovéto:

-Bez čísel nemůžete popsat problém uživatelům a organizaci.

Když všechno, co můžete říci je “ je to příliš pomalé“, nebo je tam příliš mnoho I/O operací, moc tím nevyjádříte. Získat spolupráci uživatelů a podporu managementu vyžaduje být schopen říci: “ Report běží 2h. 38 min a tak nemůžeme končit před 11“, nebo “ Průměrný update trvá 13 sec, ale ve špičkách jsem naměřil 49.“.

-Bez čísel nemůžete dosáhnout významných pokroků, nemůžete vyjádřit číselně míru zrychlení a vytyčit si jasné cíle.

-Bez čísel nemůžete vyjádřit své pokroky

 

Čísla potřebujete pro změření malých úspěchů a pro rozhodování mezi alternativními možnostmi.

 

 Př:Zjišťování času ve 4gl

 

DEFINE start_time Datetime HOUR TO FRACTION(2) ??

Elapsed INTERVAL MINUTE (4) TO FRACTION(2)

LET start_time=EXTEND(CURRENT,HOUR TO FRACTION(2))

 

{měřená část}

LET elapsed= EXTEND(CURRENT,HOUR TO FRACTION(2))-start_time

DISPLAY “Elapsed time was“,elapsed

 

PS: CURRENT dává čas normální, pokud chceme skutečný čas běhu, jsou na to C funkce, které můžeme volat z 4gl programů a ACE reportů.


 

Nalezení vinných funkcí

 

 Jedním z lepších zvyků je, že ve většině programů je malá část kódu(20 %nebo méně) měří čas běhu jednotlivých částí programu.

 

 

Optimizér *obsah

 

Optimizér je část databáze, která rozhoduje jak provádět dotazy. Jeho nejdůležitější práce je rozhodovat pořadí tabulek. K provedení takového rozhodnutí se rozhoduje k nejefektivnějšímu přístupu k jednotlivým tabulkám(sekvenčně, přes index, přes dočasný index) a musí rozhodnout, kolik řádků každé tabulky se bude podílet na konečné odpovědi.

 

Návrh optimizéru není vědecký a optimizér je částí databáze, která se pořád vyvíjí a zlepšuje.

My bereme v potaz verzi 4.1 a starší. 


Důležitost pořadí tabulek

 

Pořadí tabulek má velký vliv na rychlost joinů, což nejlépe uvidíme na příkladech

  

Join bez filtrů

 

SELECT C.customer_num, O.order_num,sum(items.total_price)

FROM customer C,orders o, items I

WHERE C.customer_num=O.customer_num

AND O.order_num=I.order_num

GROUP BY C.customer_num, O.order_num

 

Představte si tabulky bez indexů. Bez indexů se nemá DBE jinou volbu, než jednoduché hnízděné cykly, takže by vyhodnocování vypadalo nějak takto:

 

For each row in the customer table do:

Read row into C

For each row in the orders table do:

Read row into O

If O.customer_num=C.customer_num then

let Sum=0

For each row in the items table do:

Read row into I

If I.order_num=O.order_num then

Let Sum=Sum+I.total_price

End If

End For

Prepare an output row from C,I ,and Sum

End If

End For

End For

  

Celkem to tedy vypadá

Všechny řádky v tabulce

Načteny

Customer

|customer|

Orders

|customer|*|orders|

Items

|customer odp|*|orders odp|*|items|

 

Toto není jediný možný plán dotazu. Jiný může pouze přehodit role customer a orders.

 

Číslo řádku v každé tabulce je vzato z systémové katalogové tabulky systables. Ve skutečnosti můžeme napsat dotaz počítající počet řádků, který může být použit v dotazovém plánu výše uvedeného:

 

SELECT C.nrows+C.nrows*O.nrows+O.nrows*I.nrows

FROM systables C, systables O, systables I

WHERE C.tabname="customer"

AND O.tabname="orders"

AND I.tabname="items"

 

Takto v podstatě optimizer předvídá rozsah práce, který vyžaduje daný plán. Řádkové účty v systables jsou měněny pouze když je vyvolán příkaz UPDATE STATISTIC, takže optimizér občas počítá se zastaralými informacemi.

 

Join se sloupcovými filtry

V předchozím případě nebyl vidět rozdíl v rozsahu práce dvou možných plánů. Účast sloupcového filtru to mění. Sloupcový filtr je WHERE výraz, který redukuje počet řádek, kterými tabulky přisůívají. Toto je předchozí dotaz s filtrem:

 

SELECT C.customer_num, O.order_num,sum(items.total_price)

FROM customer C,orders o, items I

WHERE C.customer_num=O.customer_num

AND O.order_num=I.order_num

AND O.paid_date IS NULL

GROUP BY C.customer_num, O.order_num

Výraz O.paid_date IS NULL vyfiltruje některé řádky, které budou použity z tabulky orders. Jako předtím jsou zde dva plány. Plán začínající orders:

 

For each row in the orders table do:

Read row into O

If O.paid_date is null then

For each row in the customer table do:

Read row into C

If O.customer_num=C.customer_num then

let Sum=0

For each row in the items table do:

Read row into I

If I.order_num=O.order_num then

Let Sum=Sum+I.total_price

End If

End For

Prepare an output row from C,I ,and Sum

End If

End For

End If

End For

 

Nechť pdnull bude počet řádků, které určí filtr:

SELECT COUNT(*) FROM orders WHERE paid_date IS NULL

 

Pak to bude vypadat:

Všechny řádky v tabulce

Načteny

Orders

|Orders|

Customer

|customer|*pdnull

Items

|customer|*|items|*pdnull

 

 

Alternativní plán by vypadal:

 

For each row in the customer table do:

Read row into C

For each row in the orders table do:

Read row into O

If O.paid_date is null AND O.customer_num=C.customer_num then

let Sum=0

For each row in the items table do:

Read row into I

If I.order_num=O.order_num then

Let Sum=Sum+I.total_price

End If

End For

Prepare an output row from C,I ,and Sum

End If

End For

End For

 

Všechny řádky v tabulce

Načteny

Customer

|customer|

Orders

|customer|*|orders|

Items

|customer |*|items|*pdnul|

 

Tyto dva plány mají stejný výsledek, přestože se jejich postup liší. Tento rozdíl však může představovat tisíce diskových přístupů.

 

Plánování s použitím indexů

 

Předchozí případy nepoužívali indexy. To bylo nerealistické. Skoro všechny tabulky mají jeden nebo více indexů, které se projevují při plánování.

S indexy by plán vypadal takto:

 

For each row in the customer table do:

Read row into C

Look up C.customer_num in index on orders.customer_num

For each matching row in the orders table do:

Read row into O

If O.paid_date is null then

let Sum=0

look up O.order_num in index on items.order_num

For each maching row in the items table do:

Read row into I

Let Sum=Sum+I.total_price

End For

Prepare an output row from C,I ,and Sum

End If

End For

End For

 

To už je velká redukce.

Ale každý plán užívající indexy musí index načíst. Je obtížné předvídat, jak mnoho stránek indexu bude třeba načíst.

Fyzické uložení tabulky může také ovlivnit cenu užití indexu. Předchozí dotaz načítá customery v fyzickém pořadí.

Když je tedy výstup v pořadí customer_number, budou se záznamy slévat, takže budou načítány pouze jednou. Pokud je fyzické uložení náhodné, může vést vyzvedání každé položky na novou stránku, což bude také dost zpomalovat.


Jak optimalizér pracuje

 

Optimizéry od 4.0 výše formulují všechny možné dotazovací plány. Pro každý plán odhadnou počet zkoušených řádků tabulek, načtených diskových bloků a (když je nainstalovaný INFORMIX-STAR) síťových přístupů, který mohou očekávat. Vyberou plán s nejmenší cenou.

 

Vstup optimizéru

Optimizér se řídí systémovými katalogy a jinými souhrnnými informacemi. Není zde čas pro dotazy typu SELECT COUNT(*) k zjištění počtu řádků v tabulce. Informace přístupné optimizéru pocházejí ze systémových katalogových tabulek. Tyto zahrnují informace o:

-počtu řádků v tabulce (v době posledního UPDATE STATISTIC)

-jestli je sloupec omezený jako unikátní

-indexy

-které sloupce

-vzestupně/sestupně

-clustery

Katalogy podporované INFORMIX-ONLINE nahrazují doplňkový vstup:

-počet diskových stránek obsazených řádkami dat

-hloubku indexu B+ stromu (míra množství práce potřebná k nahlédnutí do indexu)

-počet diskových bloků obsazených indexem

-počet unikátních položek v indexu (dělených počtem řádků-pro odhad kolik řádků bude souhlasit s daným klíčem)

-druhá největší a druhá nejmenší hodnota v indexovaném sloupci

(snaží se vyhodit extrémní hodnoty, optimizér předpokládá, že hodnoty jsou rovnoměrně rozloženy mezi těmito)

 

Přístupový filtr

Optimizér nejdříve zkouší výrazy ve WHERE a kouká se po filtru. Oceňuje zvlášť pro každý filtr. Selektivita je číslo mezi 0 a 1, které značí část řádků, o kterých si optimizér myslí, že projdou. Hodně vybíravý filtr dostane 0, filtr málo filtrující dostane 1.

Optimizér si tedy poznamenává tyto fakta o dotazu

-Jestli je vhodný index.

Když jsou vybírány jenom indexované sloupce, je rychlejší číst pouze indexové stránky a ne celé řádky (To je často možné v poddotazech.).

-Jestli index může být použit k hodnocení filtru.

Pro tento účel je za indexovaný sloupec považován ten, co má index nebo ten, který je v nějakém složeném indexu na prvním místě. Zde můžeme uvažovat různé možnosti:

-Když je sloupec porovnáván se znakem, hostitelskou proměnou, nebo zvláštním poddotazem,

nástroj bude moci užít index v půběhu načítání řádek

-Když je indexovaný sloupec porovnáván se sloupcem v jiné tabulce(join)

-Jestli index může být použit v ORDER BY (třídění)

-Jestli může být index využit v GROUP BY

 

Vybrání přístupové cesty

Pak vybere optimizér nejlepší způsob přístupu do tabulek z dotazu. Má tři možnosti

-sekvenčně

-podle indexu

-vytvořit dočasný index a použít ho

Volba mezi prvními dvěmi způsoby závisí na tom, kolik odfiltrují filtry. Když je dostatečný filtr na indexovaném sloupci, přistupuje se pomocí indexu.

 Když zde není filtr, musí přečíst všechny řádky. Je obvykle rychlejší jednoduše číst řádky než čtení řádků přes index. Když se však řádky očekávají seřazené, můžeme ušetřit přímým čtením méně než řazením.

Dočasný index vytváří ve dvou případech

-Když žádná tabulka v joinu nemá na spojovaném sloupci index a tabulky jsou dostatečně velké,

může se optimizér rozhodnout, že je rychlejší vystavět index na tabulku, než číst celou tabulku pro každý řádek druhé.

-Můžete také použít dočasný index pro tříděné nebo groupované sekvence. (Alternativa je dočasná tabulka, která se pak setřídí.)

 

Vybrání plánu dotazu

Se všemi těmito dostupnými informacemi, optimizér generuje všechny možné dotazy pro joinování tabulek v páru. Potom, když jsou joinovány více než 2 tabulky, užije optimizér nejlepší dvoutabulkové plány k připojení dvou tabulek ke třetí, třech ke čtvrté a tak dál.

Optimizér přidá cenu koncových prací pro kompletní joinovací plány. (ORDER BY,GROUP BY)

Konečně optimizér vybere nejmíň náročný plán a předá ho hlavní části k zpracování.


Čtení plánu

 

Volba optimizéru nemusí být tajemstvím. Můžete si vyhledat přesně, co je plán. Zapněte volbu SET EXPLAIN ON před tím, než vykonáváte dotaz. Na počátku dalšího dotazu optimizér vypíše vysvětlení jeho plánu do konkrétního souboru (jeho jméno a umístění závisí na operačním systému)(sqexplain.out). Ceny vypisuje v jednotlivých přístupech na disk, jiné akce jsou na to přepočítávány.

 

 

Časová cena dotazu *obsah

 

Nejvíce času enginovi zabírají při provádění dotazů dvě věci

-čtení dat

-porovnávání sloupcových hodnot s jinými.

Z těchto je čtení daleko pomalejší.

Tato část bude o tom, kde engin tráví čas, bude prozkoumávat vztahy pro tvorbu rychlejších dotazů.


Aktivity v paměti

 

Engin může s daty pracovat pouze v paměti. Musí je načíst do paměti před jejich porovnáváním s filtry. Musí načíst řádky z obou tabulek, než začne testovat joinovací podmínku. Engin si připravuje výstup v paměti konstrukcí vybraných sloupců z jiných řádků v paměti.

Většina z těchto aktivit jsou velmi rychlé. V závislosti na počítači engin může provést stovky nebo dokonce tisíce porovnání za sekundu. Čas strávený prací v paměti je obvykle zlomkem z celého času provedení dotazu.

Dvě aktivity v paměti mohou trvat dlouhou dobu.

-třídění

-porovnávání pomocí LIKE a MATCHES.

Některé typy dotazů, zvláště testy jeden nebo více znaků před nebo uprostřed hodnoty jsou dost drahé.


Řízení diskového přístupu

 

Trvá déle číst řádky z disku než testovat řádky přímo v paměti. Hlavním cílem optimizéru je redukovat data, která musí být čtena z disku, ale může eliminovat pouze nejvíce zřejmé neefiktivity.

 

Diskové bloky

Engin rozděluje disk na bloky pevné délky. Stejná velikost je používaná pro všechny databáze řízené jedním enginem. Indexy jsou také ukládány v blocích.

V INFORMIX-ONLINE je velikost bloku nastavena při inicializaci. (Obvykle 4 kB). U Jiných engininů INFORMIXU,které využívají cizí souborový operační systém, velikost bloku záleží na něm (typicky 1kB). Je možné definovat tabulky široké jako blok (některé enginy dovolují řádkům přesahovat velikost bloku ). Typiská velikost řádku je mezi 50 a 200 B,takže typisky blok obsahuje 5-50 řádků. Indexová položka obsahuje klíč a 4Btový pointer, takže blok indexu typicky obsahuje 50-500 položek.

Vyrovnávací paměť stránek

Engine má kus paměti vyhražen pro kopie diskových bloků, které byly v poslední době čteny. Zůstává v naději, že tyto stránky budou znovu potřeba. Když se jeho očekávání splní, nemusí znovu přistupovat na disk.

Podobně jako u bloků, počet vyrovnávacích pamětí závisí na enginovi a souborovém operačním systému.

 


Cena čtení řádky

 

Když si engin potřebuje otestovat řádek, musí ho přečíst z disku. Při tom nečte jeden řádek, ale blok, který ho obsahuje (Když je řádek delší než blok, přečte tolik bloků, kolik je nezbytné.). Cena přečtení bloku je základní jednotka práce, kterou optimizér užívá pro své výpočty. Skutečná cena načtení bloku je proměnná a těžko předvídatelná. Je to kombinace následujících faktorů:

-Vyrovnávací paměti

-Přístupu více aplikací ke stejnému bloku

-Seek time

-Reakční čas

Cena načtení bloku může kolísat od mikrosekund (když je ve vyrovnávací paměti) přes několika milisekund do stovek milisekund.


Cena sekvenčního přístupu

 

Disková cena je nejmenší, když se čte v pořadí, v kterém jsou data uložena na disku (každý blok načten pouze 1x).

Pokud je engin jediný program na disku, cena seeku je také minimalizovaná. Souvislé řádky jsou obvykle v souvislých blocích, takže se hlavy posouvají málo o málo. Dokonce když není důvod, groupování souvislých bloků probíhá souvisle, takže nejsou potřeba dlouhé posuny.

Dokonce reakční doba může být při sekvenčním čtení nižší. To závisí na HW a na souborovém operačním systému. Disk je obvykle nastaven k minimalizaci reakční doby, ale je možné, že disk potřebuje celou otáčku, než je schopen načíst další blok, což drasticky zpomaluje dobu přístupu.


Cena nesekvenčního přístupu

 

Cena disku je větší, když jsou řádky vyzvedávány v jiném pořadí, než je jejich fyzické uložení. Normální tabulky jsou mnohem větší, než vyrovnávací paměť, takže jen malá část tabulky může být v paměti. Když je tabulka čtena zpřeházeně, jen málo řádků najdeme ve vyrovnávací paměti. Obvykle je pro každý řádek čten blok.

Když čteme zpřeházeně, je zde obvykle velké časové zdržení i rotační prodleva. Zkrátka při nesekvenčním čtení je přístup mnohem pomalejší než při sekvenčním.


Cena přístupu podle ID

 

Nejjednodušší forma nesekvenčního přístupu je přístup pomocí rowid. Rowid specifikuje fyzické uložení řádku a jeho blok, takže jeho cena je podobná jako při sekvenčním.


Cena indexového přístupu

 

Zde je přidaná cena vážící se k nalezení řádky přes index. Index sám je uložen na disku a musí být načten do paměti.

Engin užívající index má dvě možnosti. Jedna je vyzvednout řádek podle klíčové hodnoty. To vypadá asi takto:

SELECT company,order_num

FROM customer,orders

WHERE customer.customer_num=orders.customer_num

Jedna tabulka, pravděpodobně customer, bude čtena sekvenčně. Její hodnota customer_num je použita k prohledání indexu na sloupec customer_num v tabulce orders. Když matchuje, je řádek přečten.

Náhled do indexu pracuje sestupně od kořenového uzlu k listům. Kořen je obvykle (protože je často používán) umístěn v paměti. Přítomnost náhodného koncového uzlu v paměti závisí na velikosti indexu a ukazuje se nepravděpodobnou. Když je tabulka hodně velká, je počet listových bloků o mnoho větší než vyrovnávací paměť, skoro každé hledání koncového uzlu musí být načteno znovu. Počet načítaných bloků je přibližně 2r, kde r je počet hledaných řádků. Ačkoliv je to drahé, oproti sekvenčnímu r2 je to zlepšení.

Engin může také číst index sekvenčně (r+i, i počet listů).


Nízká cena malých tabulek

 

Každá tabulka, která se vejde do vyrovnávací paměti je malá (cca 4 bloky a méně).


Cena síťového přístupu

 

Přesun dat přes síť je, co se týče prodlev, ošidný.

Rozeznáváme tu dva přístupy

-přes INFORMIX-NET aplikace posílající dotazy jinému stroji.

-přes INFORMIX-STAR (distribuovaná data), rys INFORMIX-ONLINE engin může číst řádky databáze z jiného stroje.

 

 

Rychlé dotazy *obsah

Obecně

-čtou málo řádků

-vyhýbají se třídění, třídí málo řádků, nebo třídí podle jednoduchého klíče

-čtou data sekvenčně

 

Jak toho dosáhnout není vždy zřejmé. Specifické metody závisí velmi silně na detailech aplikace a databáze. Následující část navrhuje obecná doporučení.


Příprava testovacího prostředí

 

Prvně vyberte jeden dotaz, který je příliš pomalý. Potom nastavte prostředí, v kterém ho chcete odhadovat, schopné opakovat dotaz. Bez tohoto prostředí si nikdy nebudete jisti, zda změna pomohla či nikoliv.

Když užíváte víceuživatelský systém nebo síť, kde se podmínky mění v závislosti na denní době, je třeba provádět experimenty ve stejnou dobu. Můžete třeba vždy pracovat v noci.

Pokud je dotaz součástí složitého programu, vytáhněte z něj SELECT a spouštějte ho interaktivně, nebo ho zabudujte do jednoduchého programu.

Skutečným dotazům trvá dlouho, než se provedou, tak si můžete připravit menší model DB, v které můžete dotazy testovat rychleji. Může to pomoci, ale musíte si být vědomi následujících problémů:

-optimizér se může rozhodovat v malé db jinak než ve velké, i když relativní velikosti tabulek jsou stejné.

Ověřte, zda dotazovací plány jsou v obou případech stejné

-Doba vykonávání je zřídka lineární funkcí velikosti tabulky.

Proto každé vaše rozhodnutí na malém modelu musí být prozatimní dokud si ho neověříte na velké.


Studium schématu

 

Studium definic všech tabulek, pohledů a indexů užitých v DB. Můžete prověřit detaily interaktivně užitím Table option INFORMIXu-SQL. Dejte dobrý pozor na indexy, datové typy sloupců užité v joinovacích podmínkách, na řazení , na pohledy. Čím lépe porozumíte tabulkám, tím lépe porozumíte dotazovacímu plánu vybranému optimizérem.


Studium Dotazového plánu

 

Užijte SET EXPLAIN ON k rozluštění užitého dotazového plánu. Zde je pár motivů:

-joinují se neočekávané tabulky.

-zmínky o dočasných souborech značí, že výstup byl napsán do dočasné tabulky a pak setříděn.

-užití sekvenčního přístupu pro druhou nebo následující tabulku v joinu značí,

že tabulka bude přečtená celá pro každý vybraný řádek každé předchozí tabulky.

-autoindex znamená, že se engin bude zdržovat konstrukcí indexu, aby se vyhnul vícenásobnému sekvenčnímu přístupu

-užití sekvenčního přístupu při procházení první tabulky může být marnotratné, když potřebujeme pouze málo řádků


Modifikace dotazu

 

 Nyní, když rozumíte, co dotaz dělá, se koukneme na způsoby jak vyhodnocování zlehčit. Následující návrhy odpovídají předchozímu seznamu.

 

Přepsání joinů prostřednictvím pohledů

Můžete přepsat joinovací dotaz na joinovací pohled joinových pohledů. Když přepíšete dotaz přímo na joinování méně tabulek, můžete dostávat jednodušší plán dotazu.

 

Vyhnout se nebo zjednodušit třídění

Třídění není nezbytně špatná věc. Enginovy třídící algoritmy jsou vylaďěny k extrémní výkonnosti. Jsou určitě tak rychlé jako některá externí třídění, která můžete aplikovat na stejná data. Pokud je třídění děláno příležitostně, nebo na málo výstupních řádcích, není potřeba se mu vyhýbat.

Ale měli by jste se vyvarovat jednoduchému opakovanému třídění velkých tabulek. Optimizér se vyhýbá třídění, jakmile může produkovat výstup ve správném pořadí automaticky užitím indexu.

Zde je několik faktorů, která zabraňují optimizéru užít index:

-Jeden nebo více řadících sloupců není zahrnuto v indexu

-Sloupce jsou vyjmenovány v jiném pořadí v indexu a v ORDER BY nebo GROUP klauzuli

-Řadící sloupce jsou brány z různých tabulek

 

Odstranění sekvenčního přístupu do velkých tabulek

Sekvenční přístup

Sekvenční přístup do tabulky vypadá na první pohled zlověstně, protože hrozí číst každý řádek tabulky pro všechny předchozí. Měli by jste být schopni rozhodnout, kolikrát to bude možná jen párkrát, ale možná stokrát či tisíckrát. Když je tabulka malá, nevadí číst ji znovu a znovu. Tabulka bude celá v paměti. Sekvenční čtení v paměti může být rychlejší než čtení stejné tabulky přes index, zvlášť když indexové stránky odstraní z paměti jiné používané stránky.

Když je tabulka větší než pár stránek, opakované sekvenční čtení je pro vykonávání smrtelné. Jedna cesta, jak tomu předcházet je nabídnout index na joinovací sloupec.

Index zabírá místo úměrně k šíři klíčových hodnot a počtu řádků. Tedy engin musí modifikovat index kdykoliv jsou řádky vkládány, mazány, nebo modifikovány. To zpomaluje tyto operace. Když je to nezbytné, můžete užít DROP INDEX k odstranění indexu po sérii dotazů, tak uvolnit místo a usnadnit modifikaci.

 

Užití sjednocení k vyhnutí se sekvenčnímu přístupu

Jisté formy WHERE klauzule přinucují optimizér k sekvenčnímu přístupu, i když index na testovaném sloupci existuje. Následující dotaz si vynucuje sekvenční přístup do tabulky orders:

SELECT * FROM orders

WHERE (customer_num=104 AND order_num>1001) OR order_num=1008

Klíčový moment je, že jsou vybírány dvě (nebo více) oddělené množiny řádků. Množina je definována pomocí relačních výrazů, které jsou spojeny pomocí OR. V příkladu je jedna množina určena (customer_num=104 AND order_num>1001) a druhá order_num=1008.

Optimizér používá sekvenčního přístupu, i když jsou sloupce customer_num a order_num indexované.

Tento dotaz můžete urychlit úpravou na UNION dotaz. Napište oddělené SELECTy pro každou množinu řádků a spojte je pomocí UNION. Zde je přepsaný předchozí případ:

SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001)

UNION

SELECT * FROM orders WHERE order_num=1008

Optimizér užije index pro oba dotazy.

 

Nahrazení autoindexů indexy

Když dotazový plán zahrnuje autoindexy na velké tabulky, berte to jako doporučení optimizéru, že by na tom sloupci měl být index. Je možné nechat engin vystavět a zrušit index, když provádíte dotaz pouze příležitostně, ale když dotaz kladete často, ušetříte čas uděláním řádného dotazu.

 

Užití smíšeného indexu

Optimizér může užít smíšený index (co pokrývá více sloupců) různými způsoby. Například unikátnost abc. Indexy na sloupce a,b,c může užít následujícím způsobem:

Vyhodnotí filtr na a, zjoinuje a k jiné tabulce , použije ORDER BY na sloupce a, ab, nebo abc

Když vaše aplikace provádí některé dlouhé dotazy a všechny třídí podle stejných sloupců, můžete ušetřit čas vytvořením složeného indexu na tyto sloupce. V důsledku vykonáte třídění jednou a uložíte výstup pro užití v každém dotazu.

 

Užití bcheck na podezřelé indexy

Na některých enginech je možné, že je užití indexu neefektivní, protože je index poškozen. Když je dotaz užívající index výslovně pomalý, užijte utilitu bcheck k otestování integrity a opravení indexu (když je to nezbytné). (utilita tbcheck je to samé pro INFORMIX-ONLINE)

 

Zrušení a přestavění indexu po UPDATE

Po velkých updatech (po přemístění čtvrtiny nebo více řádků tabulky) se struktura indexu může stát neefektivní. Když se index zdá být méně efektivní, než by měl být a přesto bcheck nehlásí žádné chyby, zkuste ho zrušit a znovu vytvořit.

 

Vyhnout se vztažným poddotazům

Korelované poddotazy jsou takové, které zahrnují vybraný seznam sloupců hlavního dotazu ve WHERE klauzuli poddotazu. Protože se odpovědi poddotazu mohou pro každý řádek lišit, je třeba poddotaz prováádět pro každý řádek. Toto může být velmi časově náročné. Naneštěstí bez vztažných poddotazů některé věci v SQL nejdou.

Když uvidíte poddotazy v časově náročném SELECTu, koukněte se, jestli je vztažný.(Vztažný není, když žádné hodnoty sloupců z hlavního dotazu nejsou porovnávány s poddotazem-to je prováděn pouze jednou), zkuste ho přepsat a vyhnout se vztahu. Když nemůžete, zkuste redukovat počet testovaných řádků, například zkuste přidat jiný výraz do WHERE, nebo zkuste vybrat patřičné řádky do dočasné tabulky a hledat pouze v ní.

 

Vyhnout se obtížným regulárním výrazům

MATCHES a LIKE podporují wildcards, zámé jako regulární výrazy. Některé regulární výrazy jsou pro engin více obtížné než jiné. Wildcarda na počáteční pozici jako v následujícím příkladu (najdi zákazníky, jejichž jméno nekončí na y), nutí engin vyzkoušet každou hodnotu sloupce:

SELECT * FROM customer WHERE fname NOT LIKE "%y"

Optimizér nemůže použít index pro takový filtr, I kdyby nějaký měl. Toto ho nutí k sekvenčnímu postupu tabulkou. Když je tento dotaz druhý nebo později v joinu, dotaz je pomalý.

Když je obtížné testování regulárních výrazů nezbytné, vyhněte se kombinaci s joinem. Nejdříve zpracujte jednu tabulku pomocí regulárního výrazu a vyberte vysněné řádky. Uložte výsledek do dočasné tabulky a připojte k jiným.

Regulární výrazy s wildcardami jenom uprostřed a nakonci porovnávaných nevylučuje použití indexu, pokud existuje, ale stejně se jedná o dost pomalou operaci. V závislostech na datech ve sloupci, můžete upravit některé výrazy na porovnávání. Např:

SELECT * FROM customer WHERE zipcode LIKE "98_ _ _"

Můžete nahradit

SELECT * FROM customer WHERE (zipcode =>"98000")AND (zipcode <99000)

 

Vyhnout se nevýchozím podřetězcům

Filtry založené na nevýchozích podřetězcích sloupců také vyžadují, aby byla každá hodnota testovaná př:

SELECT * FROM customer

WHERE zipcode[4,5]>"50"

Optimizér neužije index i když existuje.

Optimizér užívá index pouze na výchozí hodnoty sloupce.

Takovýto dotaz může být často přepsán jako BETWEEN test na celý sloupec, a může být rychlejší.


Užití dočasných tabulek k urychlení dotazů

 

Vystavění dočasné setříděné podmnožiny tabulky může někdy urychlit dotaz. Může vám pomoci vyhnout se vícenásobnému třídění a může zjednodušit I práci optimizéru.