Syntax highlighting of Archiv/Databázové modely a jazyky/SQL

{{zarovka|1=
tabulka s RČ zákazníků a počtem jejich výpůjček,
:přičemž zákazníci jsou z Prahy a mají vypůjčeny aspoň dvě kopie, 
:tabulka je setřízená sestupně): 
<pre>SELECT rod_č, COUNT(č_kopie) AS počet_kopií
  FROM Výpůjčky V, zákazníci Z
    WHERE V.rod_č = Z.rod_č AND Z.adresa LIKE ‘%Praha%‘
  GROUP BY V.rod_č
    HAVING COUNT(č_kopie) > 2
  ORDER BY počet_kopií DESC
</pre>
|2='''Sémantika SQL'''
}}
=== SQL a jeho standardy (🎓🎓🎓) ===
{{TODO| projit a doplnit podle zkazky}}
{Zkazky|* '''SELECT - srovnani SQL-89 a SQL-92 (2014, Skopal)''' - Az ve standardu SQL-92 pribyly prikazy spojeni, do te doby se musel pouzivat kartezsky soucin jako SELECT * FROM table1, table2 Pomoci klicovych slov definovanych standardem SQL-89 neslo ziskat vysledek ekvivalentni vysledku, kde je pouzit OUTER JOIN. Vnejsi spojovani muze do vysledku zahrnout null hodnoty, ale kartezskym soucinem to neudelame. 
* '''SQL standardy (2011, Pokorny)''' - pohoda, rikam si. Nejak jsem to tam vypsal, co se ktery rok udalo. Projizdel to a pak se zarazil u rekurzivniho SQL - to byla zasadni chyba, ze jsem zminil! Hned se v tom zacal hrabat a padala slova jako Minimalni pevny bod, Tranzitivni uzaver a jine sproste vyrazy. Docela jsem si zaplaval, ptz hledat Min PB v SQL vyrazech neni zrovna moje kazdodenni hobby. Neco jsem tam nakonec vzdy vymyslel, zkousejici byl hodny a trpelivy. Nakonec se tvaril v pohode. Ne horsi nez 2, vypadal spokojene
* '''SQL SELECT (2009, Skopal)''' - Mal to byt popis syntaxe. Teda co vsetko sa da selectom zapisat. Kolko ma casti, co robia, opytal sa ako sa vyhodnocuju, popisal som rozne spojenia a pokracovali sme pokecom nad vnorenymi dotazmi a fungovanim IN, ALL, EXIST. Tiez sme niekde po ceste chvilu kecali o agregovani riadkov, agregacnych funkciach. Tiez celkom v pohode. 
}}
Je to neproceduralni jazyk slouzici pro praci se SRBD. Nerika jak se to, co chceme, ma udelat, ale jen co se ma udelat. Implementacni detaily nechava na databazi. 
Jednotlive databaze (ORACLE, MS-SQL, MySQL, ...) maji mirne odlisne dialekty SQL, i kdyz existuji standardy (sql86, sql89, sql92, sql1999, sql2003, sql2006). V zakladnich vecech se krome nazvu datovych typu ovsem moc nelisi.

Praci s nim lze rozdelit na dve hlavni pouziti:
;DDL - data definition language
*create/alter/drop table/index/trigger/sequence/view
*pr. (oracle syntaxe):
 create table  testovaci_tabulka (
     cislo number(5,1) primary key,
     retezec varchar2(123),
     datum date not null);
:vytvori tabulku testovaci_tabulka obsahujici tri sloupecky - cislo, do ktereho se vejdou cisla se ctyrmi cislicemi pred a jednou za desetinnou carkou. Sloupecek cislo je PK tabulky. Dale retezec pro ulozeni az 123 znaku dlouheho retezce a datum, ktere nemuze byt prazdne.
;DML - data manipulation language
*insert/update/delete/select
*insert into testovaci_tabulka (cislo, retezec, datum) values (4.3, 'ahoj svete!', to_date('17.1.2007', 'dd.mm.yyyy'));

==== Standardy SQL ====
* SQL-86
**SQL-89 minor revision
* '''[http://en.wikipedia.org/wiki/SQL-92 SQL-92]''' významná revize (pohledy, přístupová práva, transakce, typy, funkce, množinové operace, CHECK constraint, ...)
** nove datove typy (DATE, TIME, VARCHAR, ...)
** pridany ruzne druhy spojeni, napr. OUTER JOIN, ktery standardem SQL-89 neslo provest (kartezskym soucinem nelze ziskat NULL hodnoty) - viz [http://cs.wikipedia.org/wiki/JOIN info o JOIN]
** ''Prikaz SELECT - srovnani standardu SQL-89 a SQL-92 Az ve standardu SQL-92 pribyly prikazy spojeni, do te doby se musel pouzivat kartezsky soucin jako SELECT * FROM table1, table2 Pomoci klicovych slov definovanych standardem SQL-89 neslo ziskat vysledek ekvivalentni vysledku, kde je pouzit OUTER JOIN. Vnejsi spojovani muze do vysledku zahrnout null hodnoty, ale kartezskym soucinem to neudelame.''
**Definovany urovne izolace transakci: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ a SERIALIZABLE
* '''[http://en.wikipedia.org/wiki/SQL:1999 SQL:1999]''' (regulární výrazy, rekurzivní dotazy, triggery, booleovské typy, ...)
** procedurální rozšíření SQL - některé objektově orientované rysy
** rekurze
** objektove rozsireni
* '''[http://en.wikipedia.org/wiki/SQL:2003 SQL:2003]''' (některé XML rysy, generátor sekvencí, MERGE, CREATE TABLE LIKE, ...)
* '''SQL:2006''' – definuje širší využití XML, integrace XQuery, ...
* [http://en.wikipedia.org/wiki/SQL:2008 SQL:2008]
* [http://en.wikipedia.org/wiki/SQL:2011 SQL:2011]


* vysvetleni joinů
** http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

=== Rekurze v SQL.  (🎓) ===
{{Zkazky|
* '''Rekurzivní SQL (Pokorny?)''' - Hned se v tom zacal hrabat a padala slova jako Minimalni pevny bod, Tranzitivni uzaver a jine sproste vyrazy. Docela jsem si zaplaval, ptz hledat Min PB v SQL vyrazech neni zrovna moje kazdodenni hobby. Neco jsem tam nakonec vzdy vymyslel, zkousejici byl hodny a trpelivy. Nakonec se tvaril v pohode. Ne horsi nez 2, vypadal spokojene 
}}
{{TODO| projít a doplnit}}
{{zarovka| 
:+ vše jedním dotazem
:+ lze využít velkou část výsledku
:- časté využití pouze malé části výsledku
:- možnost zacyklení rekurze
|vyhody/nevyhody}}
* SQL před standardem SQL:99 neobsahoval možnost konstrukce rekurzívních dotazů
{{collapse|podpora v reálných DB|2=&nbsp;
* ktere DB systemy podporuji rekurzi ( http://stackoverflow.com/questions/324935/mysql-with-clause )
** MS SQL podporuje od verze MS SQL Server 2005
** Orace od 9i release 2
*** Oracle pro rekurzi obsahuje také proprietární řešení (s omezenějšími možnostmi) s pomocí speciálních klauzulí START WITH a CONNECT BY příkazu SELECT
** MySQL ne (feature request od 2006: http://bugs.mysql.com/bug.php?id=16244)
** SQLite podporuje az od 2014-02-03 (3.8.3) ( http://www.sqlite.org/changes.html )
* online vyzkouseni: http://data.stackexchange.com/stackoverflow/query/new
** priklad s konstrukty bez smyspluplne rekurze:
  WITH UsersAndPosts (CreationDate, DisplayName)
  AS
  (
      SELECT p.CreationDate, u.DisplayName
      FROM Posts AS p INNER JOIN Users AS u ON p.OwnerUserId = u.Id
        [UNION ALL]       // nepovinne
        rekurzívní člen   // nepovinne
  )
  SELECT * FROM UsersAndPosts

}}
====Common Table Expression (CTE)====
* deklaruje se klíčovým slovem ''WITH RECURSIVE jméno_CTE[(jméno_sl[,jméno_sl]…)] AS (CTE_definice_dotazu)''
* V CTE pro tabulku R se lze odkazovat na R
* vytvoří se dočasná tabulka (existuje pouze v době vyhodnocování dotazu)
<pre>
WITH RECURSIVE
  ukotvení (inicializační poddotaz) - spouští se jednou
  UNION ALL
  rekurzívní člen - opakovaně
    •rekurze běží pokud není přidán žádný další záznam anebo není překročený limit rekurze (MAXRECURSION)
    •pozor na zacyklení rekurzívního členu
    INNER JOIN - spojení s minulým krokem
  SELECT
    •Vnější SELECT - dá výsledek dotazu(výstup)
</pre>
'''Příklad:''' Najdi všechny nadřízené Nového (včetně něho sama)
<pre>
WITH RECURSIVE Nadřízení(jméno, č_nad, č_zam) AS
(SELECT jméno, č_nad, č_zam
  FROM Zaměstnanci
  WHERE jméno = 'Nový'
  UNION ALL
SELECT Z.jméno, Z.č_nad, Z.č_zam
  FROM Zaměstnanci AS Z
  INNER JOIN
  Nadřízení AS N
  ON N.č_nad = Z.č_zam)
SELECT * FROM Nadřízení
</pre>

{{Collapse|Příklady|
;Příklad z přednášky:
Tabulka: Zaměstnanci(č_zam, jméno, funkce, č_nad)

Najdi všechny nadřízené Nového (včetně něho sama)
<pre>
WITH RECURSIVE Nadřízení(jméno, č_nad, č_zam) AS
    (SELECT jméno, č_nad, č_zam
        FROM Zaměstnanci
        WHERE jméno = 'Nový'
        UNION ALL
    SELECT Z.jméno, Z.č_nad, Z.č_zam
        FROM Zaměstnanci AS Z
            INNER JOIN
            Nadřízení AS N
            ON N.č_nad = Z.č_zam)
SELECT * FROM Nadřízení
</pre>

;Příklad:
Mame tabulku Zamestnanci(jmeno, plat, vedouci). Najdete pomoci rekurzivniho dotazu vsechny zamestnance s platem nad 100 000, kteri jsou (i neprimi) podrizeni Ryby. 

<pre>
WITH RECURSIVE PodRybou(jméno) AS 
    (SELECT jméno
        FROM Zamestnanci
        WHERE vedouci = “Ryba”
        UNION ALL
    SELECT jméno
        FROM Zaměstnanci Z, PodRybou P
        WHERE Z.vedouci = P.jmeno
)
SELECT * FROM PodRybou
WHERE plat > 100 000
</pre>
}}
{{Zdroje|
* [http://www.ksi.mff.cuni.cz/~pokorny/dj-new/DJ2-3-rekurze.pdf http://www.ksi.mff.cuni.cz/~pokorny/dj-new/DJ2-3-rekurze.pdf]
}}

=== Algoritmy implementace relacních operací. Vyhodnocování a optimalizace dotazů (🎓) ===
{{Zkazky|
* '''SQL + vyhodnocovanie a optimalizácia dotazov (Richta)''' - bol super, dokonca mu nevadilo, že som zabudol popísať optimalizáciu, stačilo len 3 vetami vysvetliť, o čo ide
* '''Implementace operací relační algebry (JOIN)'''
}}
{{TODO| doplnit z wordu}}

* http://kocour.ms.mff.cuni.cz/~pokorny/vyuka/dj1/DJ1-vyhodnoceni.pdf 
* http://kocour.ms.mff.cuni.cz/~pokorny/vyuka/dj1/DJ1-optimalizace.pdf
CPU je rychle a levne, RAM je taky relativne dost, dulezity je pocet pristupu na disk

indexace je delana b+ stromy s vysokym poctem nasledniku (50-100), ale tak, aby se jeden uzel vesel do jedne stranky na disku a byla nizka uroven (pocet pater) indexu
:'''p<sub>R</sub>''' – počet stránek potřebných k uložení relace R (záleží na velikosti jednoho záznamu relace a velikosti jedné stránky, tzn. na blokovacím faktoru)
:'''b<sub>R</sub>''' – blokovací faktor pro relaci R (počet záznamů dané relace, které se vejdou do jedné stránky)
:'''I(A)''' – hloubka indexu (resp. výška B+ stromu indexu pro atribut A)

==== 1. selekce ====
SELECT * FROM R WHERE A = 'a'

ruzne vysledky podle toho, zda A je PK (unique), sekundarni klic (nemusí být unique), A je hasovany klic. Předpokládáme rovnoměrné rozložení hodnoty A v záznamech relace.
* sekvencni vyhledavani - v nejhorsim pripade je potreba prohledat celou R, v průměrném případě, je- li A PK stač í prohledat půlku (PK zarucuje unikatnost, v okamžiku, kdy naleznu první záznam, nemusím pokračovat)
* binarni vyhledavani (je-li R usporadana podle A) - log2(p_R) pro PK, pripadne plus nacteni dalsich bloků se shodnou hodnotou, neni-li to PK
* existuje-li index
** I(A) + 1 (pro PK)
** I(A) + n<sub>R</sub>(A='a') / b_R – je-li clusterovany index (tabulka je ulozena na disku setridene, index na bloky - stejne usporadani jako indexsekvencni soubor)
** I(A) + n<sub>R</sub>(A='a') – pro normalni neclusterovaný index (index ukazuje na n<sub>R</sub>(A='a') adres)
* vyhledani s hasovanim – přibližně jeden pristup (záleží na hašovací funkci).

==== 2. vypocet spojeni ====
SELECT * FROM R, S WHERE R.A = S.A

dva typy implementace
*	nezávislé relace
*	s ukazateli (záznamy jedné relace mají ukazatele na odpovídající prvky druhé relace)
spojovaci atribut A, p<sub>R</sub> <= p<sub>S</sub>

binarni spojeni - zakladni metody hnizdene cykly, trideni- slevani, hasovane spojeni, kartezsky soucin (spec. případ spojení)

;a) hnízděné cykly -
* a1)naivne ∀ r in R do ∀ s ∈ S do jestlize spojeni techto dvou radku patri do vysledku, tak ho zapis
* a2) lepe po strankach - mensi relaci jako vnejsi for (vnitrni prectu p<sub>R</sub>*p<sub>S</sub>/(pocet stranek p<sub>R</sub>, ktere muzu cacheovat (pro velke M)) krat, vnejsi p<sub>R</sub>krat, takze je lepsi, kdyz je p<sub>R</sub> mensi); pokud se mi cele R vejde do pameti, tak staci jen p<sub>R</sub>+p<sub>S</sub> cteni
* a3)se selekci - nejdrive selekci a pak spojeni (najdu selektovany prvek, pak odpovidajici v druhe tabulce, dotazy do indexu +2)
* a4)spojeni vice relaci:
** heuristika: Srovnej n relaci do cyklu algoritmu tak, aby mensi byly vnejsi.
** Pro R<sub>n</sub> (nejvnitrnejsi) alokuj jednu stranku, zbytek rozdel rovnomerne. Kdyz to nejde, tak vetsi M<sub>i</sub> pridel vnejsim relacim
;b)setrideni-slevani
* zvlaste vhodne, pokud jsou R, S setridene, jinak je treba je setridit(potrebujeme pomocny prostor). Vysledek spojeni bude taky setrideny podle A
* b1) klasicke trideni na vnejsi pameti, pak slevani. Pokud M > sqrt(pS), tak lze 2 behy setridit - 3(pS + pR) cteni a 2(pS+pR) + pSR zapisu.
* b2) varianta s ukazateli (prvky R obsahuji ukazatele na prvky S) - setridit R podle ukazatelu a pak jen cist S (nemusi byt setrizena) - 3pR + pS cteni + zapis vysledku
* Porovnani s hnízděnými cykly:
** |pS - pR| male - lepsi je trizeni slevani
** |pS - pR| velke - lepsi jsou hnízděné cykly
;c) hasovani 
* nejsou-li indexy pro R.A a s.A, nemusi-li byt vysledek setrizen (jde taky vyrobit vysledek a pak ho dodatecne setridit)
* c1) klasicke hasovani (predpokladame, ze se R vejde do pameti) - zahesuj R do pameti, prochazej S, hasuj s.A a primym pristupem najdi patricne r \in R. Pokud patri do vysledku, tak ho uloz do vystupniho bufferu.
* c2)spojeni s rozdelovanim relaci (R se nevejde cele do pameti, jen jeho cast)- jako c1, ale na nekolikrat, na kolikrat se nam R vejde do pameti - pR + pS*x (pocet cyklu) cteni
* c3)GRACE algoritmus - rozdel pomoci hashovaci funkce R i S do kapes ukazatelu (skupiny ukazatelu na prvky se stejnym hashem). Pro kazdou kapsu zvlast nacti do pameti a otestuj R.A = S.A a pripadne zapis do vystupniho bufferu. Vhodne, pokud se mi jednotlive kapsy vejdou do pameti.
{{collapse|GRACE algoritmus (grace hash join)|2=
This algorithm avoids rescanning the entire S relation by first partitioning both R and S via a hash function, and writing these partitions out to disk. The algorithm then loads pairs of partitions into memory, builds a hash table for the smaller partitioned relation, and probes the other relation for matches with the current hash table. Because the partitions were formed by hashing on the join key, it must be the case that any join output tuples must belong to the same partition.

It is possible that one or more of the partitions still does not fit into the available memory, in which case the algorithm is recursively applied: an additional orthogonal hash function is chosen to hash the large partition into sub-partitions, which are then processed as before. Since this is expensive, the algorithm tries to reduce the chance that it will occur by forming as many partitions as possible during the initial partitioning phase.

*„školní“ verze
Datové struktury: n-tice R a S, kapsy ukazatelů HRi, HSi,
i ∈ {0,1,…,m-1}
hašovací funkce h: dom(A) → <0,m-1>
Algoritmus:
<pre>for k:=1 to nR do begin i :=h(R[k].A); HRi := HRi ∪ {k} end
for k:=1 to nS do begin i :=h(S[k].A); HSi := HSi ∪ {k} end
for i:=0 to m-1 do
begin POMR := ∅; POMS := ∅;
foreach j ∈ HRi do begin r:=R[j]; POMR:=POMR∪{r} end;
foreach j ∈ HSi do begin s:=S[j]; POMS:=POMS∪{s} end;
foreach s ∈ POMS do /* ve vnitřní paměti */
begin foreach r ∈ POMR do
begin if s.A = r.A then begin u:= r * s; WRITE(u)
end
end
end
end</pre>
⇒ pR + pS + nR + nS čtení
vhodnost: když pR /m + pS/m < M
;GRACE s ukládáním rozdělených relací
•M ≥ √(pR*F)
# Zvol h tak, že R lze rozdělit do m = √(pR*F) částí;
# Čti R a hašuj do (výstupních) bufferi, (0 ≤ i ≤ m-1);
#:if bufferi je plný then WRITE(bufferi);
# Proveď (2) pro S;
# for i :=0 to m-1 do begin
## Čti Ri a hašuj do paměti velikosti √(pR*F);
## Čti s ∈ Si a hašuj s.A.
:Existuje-li r ∈ Ri a s.A = r.A, generuj výsledek.
end
Zdůvodnění 4.1: předpoklad - Ri ≈ stejné velké
pR/m = pR/ √(pR*F) = √(pR/F)
Ri vyžaduje prostor F√(pR/F) = √(pR*F)
⇒ 3(pR + pS) I/O operací
:vhodnost: když pR /m + pS/m < M
:poznámky:
*Si mohou být libovolně velké. Vyžadují 1 stránku paměti;
*problém, když V(A,R) je malý;
*vhodné v situacích, když R(K,…), S(K1,K,…);
*nevejde-li se Ri resp. Si do M-2 stránek ⇒ rekurze
tj. Ri se rozdělí na Ri0, Ri1,...,Ri(k-1) stránek;
}}
* c4)jednoduche hasovani - spec. pripad GRACE - zvol h() tak, aby rozdelila R na R1, ktera se vejde do pameti (M-2) a R2, kterou budu ukladat na disk. Cti a hasuj S. Pokud h(s.A) = h(R1.A), pak porovnej v pameti a vysledek zapis. Pokud ne, uloz na disk do S2. Po projiti celeho S se z R2 stava R a z S2 se stava S.
* C5)hybridni - kombinace C3) a C4). Zvolime h tak, ze R0 se vejde do pameti cela a pro Ri nam tam zbyde jedna stranka. Hasujeme a Ri ukladame na disk. Hasujeme S a pokud padne do prostoru R0, tak porovname a zapiseme, pokud ne, tak ulozime na disk do prislusne "kapsy" Si. Po projiti pokracujeme stejne jako GRACE (v prvnim kole jsme rovnou vyresili prvni skupinu)
* Porovnani:
** C5 nejlepsi
** C4 lepsi nez C3 pro vetsi M
** C3, C4, C5 lepsi nez setrideni-slevani
dalsi operace - GROUP BY, DISTINCT se resi pres hasovani, nebo rozdelenim pomoci indexu (pokud je), pripadne trizenim

====Optimalizace====
pozn. cast s algebraickou opt. vs plan vyhodnoceni je zmatena, protoze nerozumim tomu, v jakem vzajemnem vztahu ty dve veci jsou.

je treba rozumet optimalizaci a danemu SRBD obecne pro optimalni navrh schematu a dotazu (napr. problem implicitnich konverzi versus indexy (dotaz select * from tabulka where sloup = 1234. pokud je sloupecek typu string (varchar2), tak se musi pred porovnanim bud hodnota sloupecku 'sloup' prevest na cislo nebo hodnotu 1234 prevest na string. Jeden z techto prevodu bude ignorovat pripadny index nad sloupeckem 'sloup' a je na danem SRBD, ktery pouzije. Lze obejit explicitnim prevodem (to_string(1234)), ke kteremu ovsem potrebujeme prakticke zkusenosti :)))

faze zpracovani dotazu:
* 1. prevod do vnitrni formy (typicky nejaka relacni algebra)
* 2. konverze do kanonickeho tvaru
* 3. algebraicka optimalizace
* 4. Plan vyhodnoceni
* 5. Generovani kodu
pro optimalizaci jsou dulezite kroky 3 a 4

'''3. algebraicka optimalizace''' - vyuziva se komutativnosti, asociativity a distribuovatelnosti jednotlivych operaci (selekce, projekce, sjednoceni, ...) k co nejvetsimu snizeni narocnosti.

Heuristiky:
* a) selekce co nejdrive
* b) projekce co nejdrive
* c) sjednotit vice operaci selekce (projekce) do jedne
Plan vyhodnoceni - strom dotazu + algoritmus pro kazdou operaci

Pro vsechny uvazovane plany se spocita odhadovana cena dotazu. To se udela s vyuzitim statistik o tabulce(tabulkach) a znalosti existence a typu indexu. Plan s nejmensi cenou se vybere.

Priklady ruznych planu a jejich cen (selekce prvni, selekce druha)

Dotazy nad vice tabulkami se resi vybranim nejlepsiho reseni pro jednu kazdou tabulku a pak vybranim nejlepsiho spojeni. spojuje se vzdy s jednou tabulkou (1 s 1, 2 s 1, ... n-1 s 1)

Slozitejsi dotaz je rozlozen na bloky (treba hlavni cast dotazu a vhnizdeny dotaz), ktere se optimalizuji zvlast.

Cost-based optimalizace – z předmětu DB klient-server (Rubač)
* databáze spočítá pro všechny možné plány vyhodnocení dotazu jeho odhadovanou cenu (na základě statistik, které si ukládá – např velikost jednotlivých tabulek, blokovací faktor, poměr mezi rychlostí paměti a disku, historgram sloupců – pro rozhodnutí, zda se vyplatí použít index nebo ne, apod.) a následně vybere nejlevnější možnost, může se ukázat, že odhady nebyly správné, v průběhu prvního spuštění dotazu se počítá doba jednotlivých kroků a nakonec se přepočítá volba algoritmu s aktuálními hodnotami - při dalším spuštění již dotaz běží optimálně
* analytik musí vědět, jak pracuje optimalizátor, aby tomu mohl přizpůsobit zápis dotazu, zároveň má v řadě databází analytik možnost napovídat optimalizátoru (např. A.ID = B.ID nastává v 15% případů, nebo u B použij index)


OLD:
==== Vyhodnocování (algoritmy implementace relacních operací) ====
* selekce
**sekvenční vyhledávání
**binární vyhledávání (zaznamy musi byt uspořádany, metoda je založena na půlení intervalu)
**existuje-li index
**vyhledani s hasovanim
* spojení
** hnízděné cykly (varianty s indexováním, vyhledáváním)
***naivne
***po strankach (mensi relaci dej jako vnejsi, vetsi vnitrni se budou cachovat)
** setřídění-slévání
** hašované spojení
*** klasické hašování
****predpokladame, ze se 1. tabulka vejde do pameti. Celou 1. tabulku zahasujeme do pameti. Sekvencne prochazime 2. tabulku, hasujeme dany prvek a kdyz se rovna jiz nahasovanemu prvku z 1. tabulky, tak zname spojeni z vysledku
*** [http://en.wikipedia.org/wiki/Hash_join#Grace_hash_join GRACE] algoritmus
****rozdel pomoci hashovaci funkce obe tabulky (vsimneme si rozdilu oproti klasickemu hasovani) do kapes ukazatelu (skupiny ukazatelu na prvky se stejnym hashem). Kazdou kapsu zvlast nacti do pameti a otestuj R.A = S.A a pripadne zapis do vystupniho bufferu. Vhodne, pokud se mi jednotlive kapsy vejdou do pameti.
*** jednoduché hašování
****předpokladame, ze se zadna tabulka nevejde do pameti a A (atribut) je UNIQUE
****zvol funkci h() tak, aby rozdelila tabulku R na R1, ktera se vejde do pameti, a R2, kterou budu ukladat na disk. Cti a hasuj tabulku S. Pokud h(s.A) = h(R1.A), pak porovnej v pameti a vysledek zapis. Pokud ne, uloz na disk do S2. Po projiti celeho S se z R2 stava R a z S2 se stava S. Opakuje se dokud R neni prazdne.
*** rekurzivní rozdělení relací
****predpokladame, ze se zadna tabulka nevejde do pameti. Jako Klasické hašování, ale na nekolikrat.
*** hybridní hašování
****kombinace GRACE a jednoduchého hašování (dava nejlepsi vysledky)
****Zvolime h tak, ze R0 se vejde do pameti cela a pro Ri nam tam zbyde jedna stranka. Hasujeme a Ri ukladame na disk. Hasujeme S a pokud padne do prostoru R0, tak porovname a zapiseme, pokud ne, tak ulozime na disk do prislusne "kapsy" Si. Po projiti pokracujeme stejne jako GRACE (v prvnim kole jsme rovnou vyresili prvni skupinu)

==== Optimalizace ====

Faze zpracovani dotazu:
* prevod do vnitrni formy (typicky nejaka relacni algebra)
* konverze do kanonickeho tvaru
* ''optimalizace''
* ''plan vyhodnoceni''
* generovani kodu
Pro optimalizaci je dulezity 3. a 4. bod. Oba body mi ale splyvaji. Jsou faze spravne rozdelene???


* algebraická
** přerovnání selekcí, projekcí, spojení
** heuristiky
*** selekce co nejdříve
*** projekce co nejdříve
*** transformace <math>\times</math> na *
*** posloupnost selekcí a/nebo projekcí nahradit jednou selekcí, jednou projekcí
*** přeskupení relací ve stromu dotazu tak, aby selekce produkující menší relace byly volány dříve
* statisticky řízená
** katalogy
** redukční faktor
** histogramy - rozdělení dat


'''Cost-based optimalizace''' – databáze spočítá pro všechny možné plány vyhodnocení dotazu jeho odhadovanou cenu (na základě statistik, které si ukládá – např velikost jednotlivých tabulek, blokovací faktor, poměr mezi rychlostí paměti a disku, historgram sloupců – pro rozhodnutí, zda se vyplatí použít index nebo ne, apod.) a následně vybere nejlevnější možnost, může se ukázat, že odhady nebyly správné, v průběhu prvního spuštění dotazu se počítá doba jednotlivých kroků a nakonec se přepočítá volba algoritmu s aktuálními hodnotami - při dalším spuštění již dotaz běží optimálně.

A '''rule based''' optimizer is an optimizer that just applies a set of rules to a SQL statement instead of looking at cost estimates in order to determine what the best way is to execute that SQL statement. Oracle actually allows you to use either the rule based or cost based optimizer, although Oracle says that rule based optimization will be deprecated in a future release, so it highly recommends the use of cost based optimization.

=== Objektové rozšírení relacního modelu dat. (🎓) ===
{{Zkazky|
* '''Objektové rozšíření relačního modelu dat (2014, Pokorný)''' - K této otázce jsem toho upřímně zase tak moc nevěděl. Jen jsem napsal, že lze definovat vlastní typy, třídy, metody, že existují pole a reference (REF) a že je to implementováno v SQL. Pak jsem s panem Pokorným vedl diskusi, kde se vyptával na různé věci, např. chtěl vědět, jestli může existovat třída sama o sobě (ne - musí být vždy uložená v tabulce), chtěl slyšel o ID v třídách, jak jsou uložené v tabulkách, kde se definují metody (ve třídách), apod. Nějak jsem to s jeho pomocí vyplodil a celkově byl myslím spokojený.
}}
[[Soubor:Svet.png|thumb|400x400px|svět db technologií]]
{{TODO|najít nějaké zdroje}}
mimo db řešení: ORM - nevýhoda: 15-20% pomalejší

bylo potřeba nějak zlepšit práci s BLOBem ⇒ rozšiřitelnost o nové datové typy a fce (standard SQL/MM)
* Oracle - cartridges
* SQL Server - cartridge
Ukotveno standardem SQL:1999:
*'''U'''živatelské '''D'''atové '''T'''ypy (UDT)
**''odlišující typy'' - pouze na předdefinovaných typech
** ''strukturované typy''
*** Abstraktní datové typy – ADT (strukturovaná data)
**** mohou mít dědění
**** podtypy (pro dědění se určují pomocí NOT FINAL)
***Pojmenované řádkové typy
*** Kolekce: ARRAY
****  LIST, BAG, SET, MULTISET (až v 2003)
**Reference - REF - umožňuje chápat data jako objekty
*** používá se 2x: jednou při definici tabulky, a pak pri odkazu 
** Třídy (může existovat třída sama o sobě?)
* '''U'''živatelské '''D'''atové '''F'''unkce/'''P'''rocedury (UDF/UDP)
** metody svázány s typem, fce ne
'''Zdroje:'''
* [http://www.ms.mff.cuni.cz/~kopecky/vyuka/dbapl/dbaslide.ppt Databázové aplikace - slidy]
* http://www.ksi.mff.cuni.cz/~pokorny/dj-new/DJ1-2-ORSRBD.pdf