Upload
kishi
View
36
Download
0
Embed Size (px)
DESCRIPTION
Univerzální kvantifikátory v relačních databázích - algoritmy. Jan B URE Š Dung NGUYEN TIEN 2007. Obsah. Úvod terminologie, univerzální kvantifkátory a jejich použití Algoritmy klasifikace dat přehled zhodnocení Množinový pohled Literatura. Terminologie. Univerzální kvantifikátor - PowerPoint PPT Presentation
Citation preview
Univerzální kvantifikátory v relačních databázích - algoritmy
Jan BUREŠDung NGUYEN TIEN
2007
Obsah Úvod
terminologie, univerzální kvantifkátory a jejich použití
Algoritmy klasifikace dat přehled zhodnocení
Množinový pohled Literatura
Terminologie Univerzální kvantifikátor
univerzálním kvantifikátorem rozumíme kvantifikátor používaný v relačních kalkulechuniverzální kvantifikátor aplikovaný na proměnnou x formule f nám říká, že daná formule je pravdivá pro všechny hodnoty xzápis: x : f(x)
Použití
V relačních databázích nachází použití v mnoha moderních aplikacích analytické operace (OLAP) data mining
„vnořené“ SELECTy = univerzální kvantifkátor
Implementace
V praxi bývá univerzální kvantifikátor implementován pomocí operátoru dělení () relační algebry
Univerzální příklad V průběhu referátu
budeme používat následující jednoduchý příklad ze života
tabulka předmět tabulka zápis
Tabulka předmět neobsahuje všechny předměty – je pouze jejich podmnožinou (např. množina předmětů určitého vyučujícího)
zápis
student_id předmět_id
Albert Analýza
Albert Překladače
Božena Analýza
Božena Databáze
Božena Grafika
Božena Překladače
Ctirad Analýza
Ctirad Grafika
Ctirad Překladače
(a) Dělenec
předmět
předmět_id
Analýza
Databáze
Překladače
(b) Dělitel
výsledek
student_id
Božena
(c) Podíl
Operátor dělení „Kteří studenti si zapsali všechny
předměty?“ Z tabulek je jasné, že odpovědí na dotaz je
Božena Operátor dělení vezme dvě tabulky –
dělence a dělitele a vygeneruje tabulku podíl
Aby se záznam mohl objevit v tabulce podíl musí se v dělenci vyskytovat spárovaný se všemi hodnotami z dělitele
Cíle referátu
Tento referát se zaměří především na algoritmy implementace operátoru dělení
přehled těchto algoritmů jejich srovnání s ohledem na vstupní data množinový pohled
„Nejlepší“ algoritmus
Každý autor o svém algoritmu pro univerzální kvantifikátory tvrdí, že je nejlepší
Který je skutečně nejlepší? Žádný! Každý se hodí pro jiná data Rychlost algoritmů závisí na stavu
vstupních dat
Klasifikace dat
Pro přehlednost a snadné srovnání algoritmů budeme brát v potaz několik různých stavů vstupních dat – „tříd“
Na základě stavu dělitele a dělence (v našem příkladu tabulek předmět a zápis)
Setřídění X Sdružení Sdružení (grouping) = GROUP BY Setřídění = ORDER Většině algortimů stačí požadavek
sdružených dat, nepotřebují data setříděná
Setřídění je speciální případ sdružení (grouping)
Sdružení je tedy silnějším předpokladem
Třídy
Ne všechny kombinace stavů tabulek jsou nám „k něčemu“
Některé kombinace nemají žádné speciální vlastnosti využitelné některým z námi probíraných algoritmů
Proto uvažujeme pouze 4 třídy dat
Klasifikace dat – třída 0 Žádné sloupce
nejsou sdružené Neuspořádaná,
náhodná data Nejzákladnější,
obsahuje všechny další důležité třídy (2, 5, 10)
zápis
student_id předmět_id
Božena Databáze
Ctirad Analýza
Ctirad Grafika
Albert Překladače
Božena Grafika
Ctirad Překladače
Albert Analýza
Božena Analýza
Božena Překladače
nesdruženo
nesdruženo
předmět
předmět_id
Databáze
Překladače
Analýza
nesdruženo
Klasifikace dat – třída 2 Tabulka zápis má
data sdružena podle sloupce předmět_id
Obecně – data sdružená podle sloupce hodnot, na jejichž základě se dělí (dělenec)
Neobsahuje žádné další důležité třídy
předmět
předmět_id
Databáze
Překladače
Analýza
nesdruženo
zápis
student_idpředmět_i
d
AlbertPřekladače
CtiradPřekladače
BoženaPřekladače
Božena Databáze
Ctirad Grafika
Božena Grafika
Ctirad Analýza
Božena Analýza
Albert Analýza
nesdruženo sdruženo
Klasifikace dat – třída 5 Tabulka zápis má
data sdružena podle sloupce student_id
Obecně – data sdružena podle sloupce, který zbyde po dělení (podíl)
Obsahuje důležitou třídu 10
předmět
předmět_id
Databáze
Překladače
Analýza
nesdruženo
zápis
student_id předmět_id
Albert Analýza
Albert Překladače
Božena Překladače
Božena Grafika
Božena Databáze
Božena Analýza
Ctirad Grafika
Ctirad Překladače
Ctirad Analýza
sdruženonesdružen
o
Klasifikace dat – třída 10 Tabulka zápis má
data sdružena podle sloupce student_id
Poté podle sloupce předmět_id
Ve stejném pořadí je sdružena i tabulka předmět podle předmět_id
předmět
předmět_id
Analýza
Databáze
Překladače
Sdruženo
zápis
student_id předmět_id
Albert Analýza
Albert Překladače
Božena Analýza
Božena Databáze
Božena Grafika
Božena Překladače
Ctirad Analýza
Ctirad Grafika
Ctirad Překladače
sdruženo sdruženo
Složitost algoritmů
Při analýze složitosti algoritmů je vstupem Tabulka dělenec (dividend) S(Q, D) Tabulka dělitel (divisor) T(D)
Q-množina odpovídá naší množině jmen studentů
D-množina odpovídá naší množině předmětů
Univerzální kvantifikátor v SQL Užití „NOT EXISTS“
SELECT DISTINCT student_idFROM zapis AS z1WHERE NOT EXISTS (
SELECT *FROM predmet AS pWHERE NOT EXISTS (
SELECT *FROM zapis AS z2WHERE z2.student_id = z1.student_id AND
z2.predmet_id = p.predmet_id))
Co vyjadřuje select?
Univerzální kvantifikátor v SQL
Předchozí select hledá každého studenta, pro kterého neexistuje žádný předmět, který by nenavštěvoval
Užití kvantifikátoru „FOR ALL“ by bylo intuitivnější, ale není ve standardu
Univerzální kvantifikátor v SQL Každý dotaz s univerzálním
kvatifikátorem lze nahradit dotazem, který používá agregační funkce
SELECT student_idFROM zapisGROUP BY student_idHAVING COUNT(DISTINCT predmet_id) = (
SELECT COUNT(DISTINCT predmet_id)FROM predmet)
Skalární algoritmy Využívají přímou shodu řádků mezi
tabulkami Pro přesnost ponecháme názvy v angličtině
Nested-loops division (NLD) Merge-sort division (MSD) Merge-group division (MGD) Classic hash-division (HD) Transposed hash-division (HDT) Hash-division for quotient groups (HDQ) Transposed hash-division for quotient groups
(HDTQ)
Nested-loops division (NLD) Nejnaivnější algoritmus, ale protože
nemá speciální požadavky na data, lze jej vždy použít
Nested-loops division (NLD)
Používá 2 sady datových struktur Jednu pro uchování hodnot dělitele
(předměty), tabulka seen_divisors Druhou pro hodnoty kandidátů
kvocientu, tabulka seen_quotients
Nested-loops division (NLD) Algoritmus
Naplníme tabulku seen_divisors(předměty) Pak zkoumáme dělenec
Pro každý řádek zjistíme, jestli je aktuální kvocient již v tabulce seen_quotients(jména studentů)
Pokud ne, přidáme do tabulky a pokračujeme iterativně a najdeme řádky se shodným kvocientem vnějšího cyklu
Pro každý takový řádek zkontrolujeme, jestli je jeho hodnota dělitele již v tabulce seen_divisors
Pokud ano, označíme tuto hodnotu Pokud na konci jsou všechny jeho dělitelé označeny,
vypíšeme aktuální kvocient(jméno studenta)
Nested-loops division (NLD)
Může být velmi neefektivní Pro každý řádek dělence může
projít až všechny řádky dělitele Typická složitost O(|S|2)
Merge-sort division Předpoklady
Dělitel T je vytříděný Dělenec S je seskupený dle Q a každá
skupina je uvnitř setříděná dle D jako T
Merge-sort division Algoritmus
Předpoklad vzestupného třídění Začneme prvním řádkem dělitele a dělence Jestli dělitel je roven hodnotě D aktuálního řádku
dělence, postoupíme na další řádek v obou tabulkách Jestli D < dělitel, postoupíme na další řádek skupiny Jestli už nejsou žádné řádky v kvocient skupině, ale
aspoň jedna v děliteli, postoupíme na další skupinu Jestli už nejsou žádné řádky v děliteli, našli jsme
kvocient
Merge-sort division
Složitost O(|S| + |Q||T|)
Merge-group division Zbobecněním MSD Oba vstupy seskupeny,nemusí
být setříděné
Merge-group division
Lze bezpečně přeskočit kvociet kandidáta, pokud aktuální hodnota Q > aktuální řádek dělitele, pokud je třídění vzestupné
Jelikož se setřídění nevyžaduje, nelze přeskočit na další skupinu při neshodě hodnot, jako při MSD
Merge-group division
Složitost O(|S| + |Q||T|)
Classic hash-division
Classic hash-division
2 hašovací tabulky pro dělitele a kvocient
Podílová hašovací tabulka uchovává kandidáta a má bitmapu ke každému kandidátovi s jedním bitem pro každého dělitele
Classic hash-division
Algoritmus Sestaví hašovací tabulku dělitele
Každý řádek s unikátním číslem index dělitele
Sestaví podílovou hašovací tabulku a doplní příslušné bity
Vypíše všechny podílové kandidáty se samými jedničkami
Classic hash-division
Složitost O(|S| + |T|)
Transposed hash-division Mírná variace HD
Transposed hash-division
Uchovává bitmapu společně s řádkem v hašovací tabulce dělitele, na rozdíl od HD
Hash-division for quotient groups
Hash-division for quotient groups
Jde o optimalizaci HD Dělenec je seskupován dle Q, tím
tedy nepotřebujeme podílovou hašovací tabulku
Transposed hash-division for quotient groups
Agregační algoritmy
Nepracují přímo s konkrétními hodnotami, místo nich pracují s počty řádek
Spočítají počet řádek náležejících každému „podílovému kandidátu“ (student v našem příkladu) a ten porovnávají s počtem řádek v děliteli (tabulka předmět v našem příkladu)
Agregační algoritmy
Nevýhody agregačních algoritmů: nedokáží se vypořádat s duplicitními
řádky (až na výjimky) nedokáží se vypořádat s „NULL“
hodnotami potřebují zajištěnou referenční
integritu (v našem příkladě odstraněny řádky s předmět_id = Grafika)
Nested-Loops Counting Division(NLCD)
„Nejnaivnější“ z agregačních algoritmů Nemá žádné požadavky na
předzpracování dat (třída 0) Stejně jako ostatní agregační algoritmy
se nevypořádá s duplicitními řádky, nulovými řádky a potřebuje zajištěnou referenční integritu
Vyžaduje mnoho průchodů tabulkou
NLCD – princip Používá dva cykly (nested loops) Na počátku projde dělitele a spočítá řádky Vnější cyklus postupně bere dělence řádek po řádku –
pokud najde takový řádek, jehož podílového kandidáta ještě nemá ve své tabulce projitých kandidátů, přidá ho tam, nastaví počitadlo na 1 a vstoupí do vnitřního cyklu
Vnitřní cyklus projde celá data a najde všechny řádky s podílovým kandidátem, který se zrovna ověřuje – pokaždé zvedne počitadlo o 1. Pokud se počitadlo rovná počtu řádků dělitele, přidá podílového kandidáta do výstupu, poté se vrátí do vnějšího cyklu
Počet řádků se drží v globální proměnné
NLCD - příklads1 = s2 = zapiswhile predmet.next() do
dpocet++;while s1.next() do
if s1.student_id not in podilhashtable then beginwhile s2.next() do
if s1.student_id == s2.student_id then beginspocet++;if spocet == dpocet begin
output s1.student_id;break;
end;end;
spocet = 1;insert s1.student_id into podilhashtable;
end;
NLCD – shrnutí Nemá žádné požadavky na data, je
proto univerzální Časová složitost je v nejhorším
případe O(|S|2 + |T|), typicky pak O(|S|2), tedy stejná, jako u NLD
Paměťová náročnost je menší než u NLD – je potřeba si držet pouze projité podílové kandidáty, tedy O(|Q|), což je v nejhorším případě O(|S|)
Merge-Count Division(MCD)
Je mnohem rychlejší než NLCD, ale za cenu omezení jen na určitá data
Potřebuje data sdružená podle podílových kandidátů (třída 5)
Stačí mu jeden průchod tabulkou
MCD - princip Na počátku opět projde tabulku
dělitele a spočítá její řádky Prochází postupně tabulku dělence –
vždy, když narazí na nového podílového kandidáta, nastaví počitadlo na 1, při vstupu na každý další řádek jej pak o 1 zvýší – pokud se počitadlo rovná počtu řádku v děliteli, podílového kandidáta dá do výsledku
MCD - příkladdpocet = 0while not predmet.isEmpty() do begin
dpocet++;předmět.next();
end;if not zapis.isEmpty() then begin
zapis.next();podilovy_kandidat = zapis.student_id;
end;while not zapis.isEmpty() do begin
spocet = 0;while not zapis.isEmpty() and zapis.student_id == podilovy_kandidat do begin
spocet++;zapis.next();
end;if spocet == dpocet then
output podilovy_kandidat;if not zapis.isEmpty()
podilovy_kandidat = zapis.student_id;end;
MCD - shrnutí
Časová složitost je v nejhorším případě O(|S| + |T|) – jeden průchod každou z tabulek
V průměrném případě pak O(|S|) Náročnost na paměť je velmi nízká,
potřebujeme pouze dvě proměnné na počítání řádků
Paměťová složitost je tedy O(1)
Hash-Division for Divisor Groups(HDD)
Jak název napovídá, potřebuje data v dělenci sdružená podle sloupce obsahujícího hodnoty z dělitele (třída 2)
Jedná se o variaci na „obyčejný“ hash-division algoritmus
„Blokující“ – žádný výstup v průběhu, výstup je generován až po projití celé tabulky
HDD - princip Prochází dělence a pro každý řádek se podívá,
jestli je podílový kandidát již v podílové hašovací tabulce – pokud ne, vloží jej a nastaví počítadlo na 1, pokud ano, zvýší počítadlo o 1
Navíc počítá kolik se již vystřídalo různých hodnot ve sloupci obsahujícím hodnoty z dělitele
Nakonec vrátí všechny podílové kandidáty z podílové hašovací tabulky, jejichž počitadlo se rovná globálnímu počítadlu
HDD - příkladzapis.next();delitel = zapis.predmet_id;dpocet = 1;while zapis.isEmpty() do begin
if zapis.student_id not in podilhashtableinsert (zapis.student_id, 0) into podilhashtable
podilhashtable(zapis.student_id).value++;zapis.next();if delitel != zapis.predmet_id then
dpocet++;end;podilhashtable.first();while podilhashtable.isEmpty() do begin
if podilhashtable.value == dpocetoutput podilhashtable.student_id;
podilhashtable.next();end;
HDD - shrnutí
Časová složitost je v nejhorším případě O(|S| + |T|), v průměrném tedy O(|S|)
Paměťová složitost je O(|Q|), tedy v nejhorším i průměrném případě O(|S|)
Transposed Hash-Division for Divisor Groups (HDTD)
Je odvozen od Transposed Hash-Division algoritmu
Potřebuje data v dělenci sdružená podle sloupce obsahujícího hodnoty z dělitele (třída 2)
„Blokující“ – žádný výstup v průběhu, výstup je generován až po projití celé tabulky
HDTD - princip
Princip algoritmu je totožný s předchozím algoritmem, pouze hodnoty se nedrží přímo v podílové hašovací tabulce, ale stranou ve vektoru – v podílové hašovací tabulce se drží index daného podílového kandidáta v tomto vektoru
HDTD - shrnutí
Časová složitost je v nejhorším případě O(|S| + |T|), v průměrném tedy O(|S|)
Paměťová složitost je O(|Q|), tedy v nejhorším i průměrném případě O(|S|)
Stream-Join Division(SJD)
Není „opravdovým“ agregačním algoritmem – má k nim ale blízko
Požaduje referenční integritu Není schopen se vypořádat s duplicitami
v děliteli Duplicity v dělenci mu nevadí Vyžaduje data třídy 5 (sdružena podle
sloupce obsahujícího hodnoty z dělitele)
SJD - princip Používá jednu hašovací tabulku podílových kandidátů, u
každého mu stačí jeden bit Na začátku vezme první skupinu (podle dělitele, tedy
podle předmětu v našem příkladě) a všechny podílové kandidáty (studenty) umístí do hašovací tabulky a nastaví jim bit na 0
Poté vždy pro každou další skupinu prochází řádky a nastaví bit na 1 všem podílovým kandidátům, které se v ní vyskytují a zároveň se vyskytují i v hašovací tabulce
Při přechodu na další skupinu jsou smazány všechny položky z hašovací tabulky, jejichž bit je nastaven na 0
Všechny bity jsou nastaveny na 0 Na konci se porovná čítač skupin s počtem řádků v
děliteli – pokud odpovídá, všechny položky, které zbyly v hašovací tabulce a mají bit nastaven na 1 jsou výsledkem
SJD - příkladzapis.next(); dpocet1 = 1; delitel = zapis.predmet_id;while not zapis.isEmpty() and delitel == zapis.predmet_id do begin
insert (zapis.student_id, 0) into podilhashtable;zapis.next();
end;while not zapis.isEmpty() do begin
if delitel != zapis.predmet_id then begindpocet1++; podilhashtable.first();while not podilhashtable.isEmpty() do begin
if podilhashtable.value == 0 then podilhashtable.delete();else podilhashtable.value = 0;
podilhashtable.next();end;
end;podilhashtable(zapis.student_id).value = 1;zapis.next();
end;dpocet2 = 0;while not predmet.isEmpty() do begin
dpocet2++; předmět.next();end;podilhashtable.first();if dpocet1 == dpocet2 then
while not podilhashtable.isEmpty() do beginif podilhashtable.value == 1 then output podilhashtable.student_id;podilhashtable.next();
end;
SJD - shrnutí
Časová složitost je v nejhorším případě O(|S| + |T|), v průměrném tedy O(|S|)
Paměťové nároky se velmi liší, závisí na počtu podílových kandidátů v první skupině – v nejhorším i průměrném případě se tedy rovnají O(|S|)
Zhodnocení algoritmů
Algoritmus dělení
Typ algoritmuTřída dat
Dělenec (S)Dělitel
(T)
Složitost
Časová Paměťová
Q D nejhorší průměrný nejhorší průměrný
NLCD agregační 0 N N N |S|2 + |T| |S|2 |S| |S|
NLD skalární |S|2 + |T| |S|2 |S| + |T| |S|
HD skalární |S| + |T| |S| |S||T| |S||T|
HDT skalární |S| + |T| |S| |S||T| |S||T|
HDD agregační 2 N G N |S| + |T| |S| |S| |S|
HDTD agregační |S| + |T| |S| |S| |S|
SJD agregační |S| + |T| |S| |S| |S|
MCD agregační 5 G N N |S| + |T| |S| 1 1
HDQ skalární |S| + |T| |S| |T| 1
HDTQ skalární |S| + |T| |S| |T| 1
MGD skalární 10 G1 G2 G2 |S||T| |S||T| |T| 1
MSD skalární S2 S2 |S||T| |S||T| 1 1
Množinový pohled
„Kteří studenti si zapsali všechny předměty?“
„Najdi studenty, u kterých množina zapsaných předmětů obsahuje jako podmnožinu množinu všech předmětů.“
Datová reprezentace množin Klasické relační databáze používají 1NF Pro ukládání množin jsou vhodnější
struktury – jednou z nich je možnost do jednoho atributu místo jedné hodnoty uložit množinu hodnot (z nějaké dané domény)
Ctirad {Překladače, Grafika, Analýza}Interní hnízděná
Ctirad PřekladačeCtirad GrafikaCtirad Analýza
Interní nehnízděná
Podmnožinové spojení
Podmnožinové spojení je operátor nad hnízděnými tabulkami
Definovaný nad dvěma relacemi R(a,b) a S(c,d) najde všechny dvojice (a,d), kde pro dané b náležející k a obsahuje jako podmnožinu c
Podmnožinové dělení
Podmnožinové spojení nemá definované chování nad nehnízděnými tabulkami (1NF)
Řeší to operátor podmnožinového dělení
Podmnožinové dělení
Tento operátor je sjednocením dílčích operátorů dělení
Pro každé unikátní d z S(c,d) vezmu množinu všech k němu náležejících c a vydělím s ní R(a,b)
Srovnání
Dělení Podmnožinové dělení Podmnožinové spojeníFormální zápis R(a,b) S(c)Levý operand (dělenec) více skupin více skupin více množinPravý operand (dělitel) jedna skupina více skupin více množinVýsledek (podíl) T(a) T(a,d) T(a,b,c,d)Formát dat 1NF 1NF ne 1NF
Literatura
Algorithms and Applications for Universal Quantification in Relational Databases (2002) Ralf Rantzau, Leonard D. Shapiro, Bernhard Mitschang, Quan Wang