Escolar Documentos
Profissional Documentos
Cultura Documentos
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
SQL. Optymalizacja
Autor: Dan Tow
Tumaczenie: Marek Paczyski (rozdz. 1 ; 6, dod. C),
Tomasz Pdziwiatr (rozdz. 7 ; 10, dod. A, B)
ISBN: 83-7361-423-0
Tytu oryginau: SQL Tuning
Format: B5, stron: 348
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treci
Przedmowa .......................................................................................................................9
Wstp ...............................................................................................................................11
Rozdzia 1. Wprowadzenie ..........................................................................................17
Po co optymalizowa zapytania SQL? ...............................................................................................18
Kto powinien zaj si optymalizacj?...............................................................................................20
Dlaczego ksika ta moe by pomocna?..........................................................................................21
Dodatek ...................................................................................................................................................23
Gotowe rozwizania..............................................................................................................................24
Spis treci
Spis treci
Tworzenie diagramw
i optymalizacja
zoonych zapyta SQL
Tworzenie diagramw i optymalizacja zoonych zapyta SQL Jak dotd, nauczylimy
si optymalizowa zapytania na rzeczywistych tabelach oraz tworzy dla nich diagramy,
ktre speniaj rne wymagania odnoszce si do normalnych zapyta biznesowych:
Zapytanie przedstawione jest na jednym drzewie.
Drzewo ma jedno rdo, dokadnie jedn tabel bez zcze z jej kluczami
gwnymi. Wszystkie wzy, inne ni wze rdowy, maj pojedyncze,
skierowane ku nim poczenia ze znajdujcymi si powyej wzami
szczegowymi, ale kady wze moe by na szczycie dowolnej iloci
skierowanych ku doowi pocze.
Wszystkie zczenia maj skierowane ku doowi strzaki
(zczenia, ktre s unikalne na jednym z kocw).
Zczenia zewntrzne s niefiltrowane, skierowane ku doowi, kolejne zczenia
znajdujce si poniej s take zewntrzne.
Pytanie, na ktre zapytanie SQL udziela nam odpowiedzi jest w gruncie rzeczy
pytaniem o encj znajdujc si na samej grze (rdo) drzewa lub odnonie
agregacji tej encji.
Pozostae tabele dostarczaj jedynie referencyjnych danych, umieszczonych
w okrelonej strukturze jedynie przez wzgld na normalizacj.
Nazwaem zapytania speniajce powysze warunki zapytaniami prostymi, chocia jak
moglimy si przekona w rozdziale 6., mog one zawiera dowoln ilo zcze, a ich
optymalizacja moe by cakiem trudna, zwaszcza w rzadkich przypadkach wzw
o podobnych wspczynnikach filtrowania lub kiedy istnieje ukryte filtrowanie zcze.
226
Zapytania, ktre nie maj tak prostej formy bdziemy nazywa zapytaniami zoonymi.
Jak poka w tym rozdziale, niektre zoone zapytania s wynikiem bdw: w projekcie
bazy danych, aplikacji lub implementacji. Bdy tego typu powoduj, e bardzo atwo
jest utworzy nieprawidowe zapytanie. W tym rozdziale nauczymy si, jak rozpoznawa
anomalie wystpujce w diagramie zapytania, ktre mog by ostrzeeniem o istnieniu
bdu w konstrukcji zapytania. Nauczymy si rwnie, jak naprawi te funkcjonalne lub
zwizane z projektem bdy, przy czym niejednokrotnie zwikszenie wydajnoci bdzie
efektem ubocznym naszych dziaa. Poprawki te przeksztacaj zazwyczaj zapytanie do
prostej formy lub na tyle do niej zblionej, aby mona zastosowa metody przedstawione w ksice wczeniej.
Niektre zoone zapytania wykraczaj poza wszystkie formy, dla ktrych opisywaem
tworzenie diagramw, wykorzystujc podzapytania, widoki lub klauzule, takie jak UNION
i UNION ALL. Takie zoone zapytania maj zazwyczaj du funkcjonalno i s czsto
spotykane, musimy wic znale metod na stworzenie dla nich diagramu oraz na ich
optymalizacj. Cel ten osigniemy poprzez rozwinicie przedstawionych wczeniej metod adekwatnych dla prostych zapyta.
227
Teoria grafw jest gazi matematyki opisujc abstrakcyjne twory zwane grafami,
ktre skadaj si z pocze i wzw, takich jak diagramy zapyta wykorzystywane w tej ksice. W teorii grafw, graf cykliczny ma poczenia w formie
zamknitej ptli. W przedstawianych dalej przykadach, a do rysunku 7.8, na
diagramach wystpuj ptle, sprawiajc, e s one diagramami cyklicznymi.
Na podstawie tego przypadku moemy wnioskowa, e SQL moe wyglda w nastpujcy sposb:
SELECT ...
FROM ... T1, ... T2, ... T3, ...
WHERE ... T1.FKey1=T2.PKey2
AND T1.FKey1=T3.PKey3
AND T2.PKey2=T3.PKey3 ...
Nazwaem klucz obcy z tabeli T1, wskazujcy na obie tabele przez FKey1, a klucze gwne
tabeli T2 i T3 odpowiednio przez PKey2 i PKey3. Poniewa wszystkie trzy zczenia
wystpuj jawnie w SQL-u, zczenie cykliczne jest oczywiste, ale naley zwrci
uwag, e dowolne z tych pocze mogoby by nieobecne. W takim przypadku przechodnio (jeli a = b i b = c to a = c) sugerowaaby istnienie tego nieobecnego warunku zczenia. To samo zapytanie moglibymy wwczas przedstawi w jednej z trzech
postaci z rysunku 7.2.
Zwrmy uwag, e w wersji A i B zapytania moemy wnioskowa o istnieniu nieobecnego poczenia z faktu, e poczenia midzy T2 a T3 maj strzaki na obu kocach, co
oznacza zczenie jeden-do-jednego. Wersja C, dla odmiany wyglda jak zwyke drzewo
zcze i mona si nie zorientowa, e ma ono cykliczne zczenia, chyba e zauwaymy, i T1 wykorzystuje ten sam klucz obcy do poczenia z T2 i T3.
228
Rysunek 7.2. To samo zapytanie cykliczne, w ktrym brakuje jednego z trzech przechodnich warunkw
zczenia
229
230
231
Dowolny porzdek, inny ni powysze cztery (taki jak (T2, T3, T1)), spowodowaby
katastrofalny nawa danych po zczeniu wiele-do-wielu z drug tabel. Byby to niemal iloczyn kartezjaski wierszy tabeli T2 i T3. We wszystkich tych bezpiecznych porzdkach
zcze tabela T1 znajduje si na pierwszym bd drugim miejscu, zanim osigniemy T2
i T3. Te porzdki zcze tworz zatem dwa zwyke zczenia wiele-do-jednego pomidzy szczegow tabel T1 a jej nadrzdnymi tabelami T2 i T3.
Rzadki filtr dwuwzowy nie ma danego dziaania w momencie osignicia pierwszej
z filtrowanych tabel, dopiero potem, po osigniciu drugiej tabeli, odrzuca cz wierszy, tak
jak to czyni zwyky filtr. Z takiej perspektywy, radzenie sobie z tym przypadkiem jest
proste zamy, e filtr nie istnieje (lub nie jest bezporednio dostpny) a do momentu zczenia z jedn z tabel, do ktrych filtr si odnosi. Jednak gdy tylko osigniemy
dowolny koniec dwuwzowego filtra, koniec przeciwny wchodzi w posiadanie lepszego
wspczynnika filtrowania i staje si bardziej atrakcyjny jako nastpny wze do zczenia.
Rysunek 7.5 pokazuje specyficzny przykad z filtrem dwuwzowym, w ktrym uamek
wierszy zwykego zczenia T1 z T2 i T3, ktre speniaj dodatkowo dwuwzowy warunek filtrowania, jest rwny 0,2. W tym przypadku wybralibymy pierwotnie porzdek
zcze niezaleny od istnienia filtru dwuwzowego, uwzgldniajc jedynie zwyke
zczenia. Jednak gdy tylko osigniemy zczenie z tabel T2 lub T3, ta druga jeszcze nie
zczona tabela otrzymuje nowy, znacznie bardziej odpowiedni wspczynnik zczenia
rwny wspczynnikowi pierwotnemu (1,0 dla T2 i 0,5 dla T3) pomnoonemu przez 0,2.
232
Zczenie z T2 w przytoczonym przykadzie jest zwykym zczeniem wykorzystujcym zagniedone ptle w indeksie na kluczu gwnym tabeli T2, wychodzc
od klucza obcego z T1. Unikajmy zagniedonych ptli w tabeli z filtrem dwuwzowym. Odnoszc si do SQL-a tu przed rysunkiem 7.5, byoby znacznie lepiej
dosign tabeli Customers, wykorzystujc ptle zagniedone przy zczeniu
T1.Customer_ID=T2.Customer_ID ni przy zczeniu dwuwzowym
T2.Region_ID!=T3.Region_ID.
233
Jeli warunek na Index_Name miaby wspczynnik filtrowania 0,0002, diagram zapytania pozbawiony pozostaych wspczynnikw wygldaby jak na rysunku 7.7.
Rysunek 7.8. czenie wieloczciowych zcze z kluczy obcych rozdzielonych na dwie tabele
234
Jeli przestrzegamy reguy, aby czy do lub z penych kluczy gwnych, najlepszy
porzdek zczenia dla rysunku 7.7 staje si jasny. Wyjdmy z filtru na Ind i podajmy
za poczeniem grnym ku IC. Jest to tak naprawd najlepszy plan wykonania dla tego
przykadu. W przypadkach takich jak ten, naley uwzgldnia niestandardowe zczenia
prowadzce do wieloczciowych kluczy gwnych tylko do momentu, w ktrym baza
danych osignie wszystkie wzy grne niezbdne do uycia penego klucza gwnego.
235
W przypadku A przedstawiem zapytanie, ktre skada si z dwch, wygldajcych na niezalene, zapyta kade z wasnymi zczeniami. W przypadku B pokazaem praktycznie
zwyke zapytanie, ktrego jedna z tabel (tabela T2) jest odczona od drzewa zczenia
(tzn. nie jest zczona z adn inn tabel). Kady z tych dwch przypadkw mapuje si
na dwa oddzielne zapytania, ktre s wykonywane w obrbie pojedynczego zapytania.
Co si stanie, jeli poczymy dwa niezalene zapytania w jedno? Kiedy dwie tabele s
poczone w jedno zapytanie bez jakichkolwiek warunkw zczenia, baza danych
zwraca iloczyn kartezjaski kad moliw kombinacj wierszy pierwszej tabeli z wierszami tabeli drugiej. W przypadku rozczonych diagramw, naley myle o wynikach
zapytania reprezentowanego przez kady niezaleny szkielet zapytania (lub izolowany
wze) jako o wirtualnej tabeli. Z tej perspektywy wida, e baza danych zwrci wszystkie
kombinacje wierszy tych dwch niezalenych zapyta. Tak wic w wyniku otrzymamy
iloczyn kartezjaski.
Kiedy spotkamy si z iloczynem kartezjaskim, tak jak pokazano na rysunku 7.9, powinnimy zbada przyczyn jego zaistnienia. Gdy j ju poznamy, bdziemy mogli
zadecydowa, ktre z wymienionych poniej dziaa podj. Bdzie to uzalenione od
tego, z ktrym spord czterech przypadkw mamy do czynienia:
Przypadek 1. W zapytaniu brakuje zczenia, ktre czyoby rozdzielone czci
Doda brakujce zczenie.
Przypadek 2. Zapytanie skada si z dwch niezalenych zapyta, a kade z nich zwraca
wiele wierszy
Wyeliminowa iloczyn kartezjaski poprzez osobne wykonywanie oddzielnych zapyta.
236
Jeli jedno z niezalenych zapyta zwraca tylko jeden wiersz, zagwarantowane jest, e
przynajmniej iloczyn kartezjaski jest bezpieczny i e zwrcona liczba wierszy bdzie nie
wiksza ni liczba wierszy zwrconych przez wiksze z niezalenych zapyta. Jednake
istnieje wci niewielki koszt poczenia zapyta. Jest on zwizany z przesyem danych,
poniewa lista SELECT poczonego zapytania moe zwrci dane z mniejszego zapytania
237
wielokrotnie, raz dla kadego wiersza zapytania wielowierszowego. Powoduje to przesy wikszej iloci zbdnych danych ni w przypadku rozdzielenia obu zapyta. Koszt
przesyu jest z drugiej strony kontrowany poprzez oszczdnoci w opnieniach wynikych z przesyu kadego pakietu zapytanie poczone oszczdza cigych odwoa
sieciowych do bazy danych, tak wic najlepszy wybr zaley od szczegw. Jeli nie rozdzielimy zapyta, optymalny plan wykonania jest prosty najpierw naley uruchomi optymalny plan wykonania dla zapytania zwracajcego pojedynczy wiersz. Nastpnie, w ptli zagniedonej, ktra wykonana bdzie tylko raz, trzeba uruchomi optymalny
plan wykonania dla zapytania wielowierszowego. Ten poczony plan wykonania ma
koszt taki sam, jak wykonanie dwch zapyta oddzielnie. Jeli plan zapytania wielowierszowego uruchomimy najpierw, plan ptli zagniedonych bdzie wymaga powtarzania dla kadego zapytania jednowierszowego tylekro razy, ile wierszy zwrcioby
zapytanie wielowierszowe.
Poczenie zapytania jednowierszowego z zapytaniem wielowierszowym jest czasem
wygodne i usprawiedliwione. Istnieje specjalny przypadek, zobrazowany na prawej
powce rysunku 7.9, w ktrym zapytanie jednowierszowe jest po prostu odczytem jedynego wiersza izolowanej tabeli T2 nie majcej adnych zcze. Iloczyn kartezjaski
z izolowan tabel jest czasem uyteczny w pobieraniu parametrw przechowywanych
w jednowierszowej tabeli parametrw, szczeglnie kiedy parametry te wystpuj jedynie
w klauzuli WHERE, a nie w licie SELECT. Kiedy zapytanie zwraca dane z tabeli parametrw, okazuje si, e tasze jest wykonanie odpowiednio poczonego zapytania ni
wykonanie dwch osobnych zapyta.
Z jeszcze rzadszym przypadkiem mamy do czynienia, gdy oba izolowane zapytania
zwracaj pojedynczy wiersz. Z punktu widzenia wydajnoci jest cakowicie uzasadnione
i bezpieczne poczenie takich dwch zapyta. Jest ono pozbawione niebezpieczestw
zwizanych z innymi przypadkami. Jednake z perspektywy programowania i konserwacji oprogramowania, czenia takich zapyta moe by mylce, a oszczdnoci s
raczej niewielkie.
238
Istniej cztery przyczyny wystpienia diagramu zapytania o wielu rdach. Nastpujca lista pokazuje te przyczyny i opisuje odpowiadajce im rozwizania:
Przypadek 1. Brakujcy warunek
W zapytaniu brakuje warunku, ktry zamieniby jedn z tabel rdowych w tabel
gwn oraz zczenie jeden-do-wielu na jeden-do-jednego.
Rozwizanie: doda brakujcy warunek zczenia.
Przypadek 2. Iloczyn kartezjaski wiele-do-wielu
Zapytanie reprezentuje iloczyn kartezjaski wiele-do-wielu na kady wiersz tabeli
gwnej, pomidzy tabelami szczegw dzielcymi wspln tabel gwn. Przypadek
ten ma miejsce, gdy wspczynnik zczenia tabeli szczegw z pojedynczej wspdzielonej tabeli gwnej do dwch rnych tabel rdowych jest wikszy ni 1,0.
Rozwizanie: usun iloczyn kartezjaski poprzez rozdzielenie zapytania na dwa
niezalene zapytania czytajce niezalenie z tabeli rdowej.
Przypadek 3. Wspczynnik zczenia tabeli szczegw jest mniejszy ni 1,0
Jedna ze rdowych tabel szczegowych czy si ze wspdzielon tabel gwn,
przy wspczynniku tabeli szczegowej zczenia mniejszym ni 1,0.
Rozwizanie: chocia nie jest to problem wydajnociowy, naley rozway odseparowanie czci zapytania lub optymalizacj jednej z czci zapytania, tak by staa si
podzapytaniem.
Przypadek 4. Tabela jest uywana jedynie dla sprawdzenia obecnoci
Jedna ze rdowych tabel szczegw nie dostarcza adnych danych potrzebnych
w licie polecenia SELECT i jest wczona do zapytania jedynie dla sprawdzenia
obecnoci.
Rozwizanie: zamieni sprawdzenie obecnoci na podzapytanie.
239
na zczenie jeden-do-jednego poprzez dodanie (lub rozpoznanie) dodatkowego warunku na tabeli Root1 (przemianowana na R1), co zapewnio, e baza danych znajdzie co
najmniej jeden wiersz w R1 dla kadego wiersza tabeli Master. Jest to szczeglnie prawdopodobne, jeli R1 zawiera szczegowe dane zwizane z przedziaami czasowymi (jak
np. zmieniajcy si podatek), ktre cz rekord gwny (jak encja podatku) i warunek
na dat (np. danie obecnej stawki podatkowej), tworzc zczenie jeden-do-jednego.
Niejednokrotnie warunek powodujcy, e zczenie staje si jeden-do-jednego, ju istnieje.
Wwczas powinnimy odkry kombinacj zczenia wiele-do-jednego i tego warunku,
ktra to kombinacja zmieni wspczynnik zczenia szczegw.
W przykadzie, w ktrym wspczynnik zczenia tabeli szczegw Root1 by
rwny 5, wspczynnik filtrowania dla takiego filtra byby rwny 0,2, lub inaczej 1/5.
240
241
eksplozja wierszy podczas czenia odpowiednich wierszy tabeli Root1 z Root2, dla
przecitnego rekordu tabeli Master. Mona traktowa Root1, jak gdyby by zczony ku
doowi, faworyzujc go nawet poprzez poprawienie jego wspczynnika filtrowania
przez owo 0,5 (w myl specjalnej reguy z rozdziau 6. dla wspczynnikw zcze tabel
szczegw mniejszych ni 1,0).
Chocia zapytanie to nie stanowi problemu z punktu widzenia optymalizacji, moe ono
by niepoprawne. Zczenie jeden-do-zera lub jeden-do-wielu z tabeli Master do Root1
ma zazwyczaj typ jeden-do-zera lub jeden-do-jednego, co prowadzi do dobrego zachowania iloczynu kartezjaskiego. Jednake jeli zczenie jest zawsze typu jeden-do-wielu,
trzeba wzi pod uwag, e rezultat moe by iloczynem kartezjaskim z powtrzeniami
dla danego wiersza tabeli Root2. Poniewa przypadek ten jest rzadki, mona z duym
prawdopodobiestwem powiedzie, e zapytanie byo zaprojektowane i przetestowane
tak, by zwracao rezultaty, ktre mapuj jeden-do-jednego z wierszami z Root2, a aplikacja moe nawet nie dziaa w innych rzadkich przypadkach.
Im rzadszy jest przypadek jeden-do-wielu, tym bardziej prawdopodobne jest, e
przypadek taki by zupenie zaniedbany w projektowaniu aplikacji.
Na przykad, jeli aplikacja wymieni dane w Root2 po odczytaniu ich za pomoc powyszego zapytania i bdzie prbowaa przesa zmiany z powrotem do bazy danych,
musi ona rozway, ktra kopia powtrzonych wierszy Root2 powinna by zapisana
ponownie do bazy danych. Czy aplikacja powinna ostrzec uytkownika kocowego, e
prbowaa wysa niespjne kopie? Jeli agreguje ona dane tabeli Root2 z zapytania, czy
unika dodawania danych z powtrzonych wierszy tabeli Root2?
242
tak naprawd jestemy zainteresowani tylko tym, czy odpowiedni wiersz z Root1 istnieje i by moe spenia jakie warunki filtrowania. Nie interesuje nas jego zawarto czy
te liczba pasujcych wierszy (poza pierwszym). W dalszej czci rozdziau zobaczymy,
jak tworzy diagram i optymalizowa zapytania z podzapytaniami tego typu.
Okazuje si, e taki przypadek jest znacznie czciej spotykany ni poprzednie przykady
niestandardowych diagramw zcze. Chocia wspdzieli on te same przyczyny problemw i te same rozwizania, co problem z wieloma wzami rdowymi, znaczna
wikszo zcze wiele-do-wielu wystpuje ze wzgldu na brak jakiego warunku
zczenia. Zacz naley od sprawdzenia, czy warunki filtrowania, ktre istniej ju
w zapytaniu powinny by traktowane jako cz zczenia, poniewa dopeniaj one
specyfikacji penego klucza gwnego na jednym z kocw zczenia. Przykad 5.2
z rozdziau 5. mg by potencjalnie takim przypadkiem, z brakujcym warunkiem
OT.Code_Type='STATUS_ZAMOWIENIA' niezbdnym, aby zczenie z OT stao si unikalne. Gdybymy traktowali ten warunek jedynie jako warunek filtrowania na aliasie OT,
zczenie z OT wygldaoby jak wiele-do-wielu. Nawet jeli nie znalelibymy brakujcej
czci zczenia pord warunkw filtrowania tego zapytania, powinnimy podejrzewa, e zostaa ona opuszczona przez pomyk.
Ten przypadek brakujcych warunkw zczenia jest szczeglnie czsty, kiedy projekt
bazy danych pozwala na wiele typw encji lub partycji w obrbie tabeli, a programista
zapomnia w zapytaniu uwzgldni warunek na typ lub partycj. Wczeniejszy przykad
tabeli Code_Translation ma rne typy encji translacji dla kadego Code_Type i nie
243
Zczenia jeden-do-jednego
Jest taki dowcip o czowieku, ktry skary si, e musi codziennie chodzi do szkoy 5 mil
pod gr w obie strony. W pewnym sensie, zczenia jeden-do-jednego zamieniaj ten obraz na sytuacj przeciwn ze wzgldu na heurystyczne reguy wybierania nastpnej
tabeli zczenia, zczenia jeden-do-jednego s w obie strony z grki! Jako takie, tego typu
zczenia nie powoduj adnych problemw z optymalizacj i s najmniej kopotliwymi
elementami diagramw zapytania. Jednake wskazuj one czasami na pewne sprzyjajce
okolicznoci do poprawienia projektu bazy danych, jeli jestemy na etapie rozwoju
aplikacji, w ktrym projekt bazy danych nie jest jeszcze zamroony. Uytecznie jest take mie standardowe sposoby na reprezentacj zcze jeden-do-jednego na diagramie.
Opisz wic sposoby przedstawiania takich przypadkw.
244
Poniewa jest to zczenie wewntrzne, przypadki jeden-do-zera pomidzy T1 a T2 tworz ukryty warunek zczenia, ktry powinien by obsuony tak, jak opisano to pod
koniec rozdziau 6. Naley take zwrci uwag, e moe to by ukryty przypadek zczenia cyklicznego, co czsto si zdarza, gdy tabela gwna czy si jeden-do-jednego
z inn tabel. Jeli tabela szczegw znajduje si powyej T1, jak wskazuje na to szare
poczenie i jeli ta tabela szczegw czy si z T1 przez ten sam klucz unikalny, ktry
zosta uyty przy zczeniu z T2, wwczas przez przechodnio tworzy si zczenie
prowadzce od tabeli szczegw do tabeli T2. Rysunek 7.16 pokazuje to implikowane
zczenie poprzez poczenie zaznaczne szarym kolorem. O tym, jak radzi sobie z takimi
przypadkami napisano we wczeniejszej czci tego rozdziau poruszajcej zagadnienie
zcze cyklicznych.
245
Rysunek 7.18. Zczenie jeden-do-zera lub jeden-do-jednego pomidzy tabelami o bardzo duej rnicy
rozmiarw
246
W tym przypadku najwaniejsze jest, aby wzi pod uwag ukryty warunek zczenia
z tabeli T1 do T2, niezalenie od tego, czy wychodzimy ze strony zapytania, po ktrej znajduje si T2, czy te osigniemy j jak najwczeniej, aby uzyska dostp do ukrytego filtru.
Rysunek 7.20. Tworzenie diagramu dla zcze jeden-do-jednego lecych pod rdow tabel szczegw
247
W razie gdy obie zczone tabele znajduj si poniej rda, naley pamita o tym, e
jeli tabele zczone jeden-do-jednego wspdziel klucz gwny, wwczas poczenie
od gry do T1 moe przez przechodnio rwnie dobrze prowadzi do T2, chyba e
prowadzi do jakiego innego klucza unikalnego wystpujcego w T1, a nieistniejcego
w T2. Tworzy si tu implikowane zczenie cykliczne przedstawione na rysunku 7.2 B.
Rysunek 7.21 przedstawia inne moliwe diagramy dla zcze jeden-do-jednego tabel,
ktre mona zakwalifikowa jako gwne tabele szczegw (nie maj zcze od gry),
jeli chocia jeden z kierunkw zczenia jeden-do-jednego ma wspczynnik zczenia
z tabel nadrzdn mniejszy ni 1,0. Ponownie mona podkreli zczenie jeden-dojednego poprzez wykorzystanie poziomego ukadu lub te podkreli, ktra tabela jest
wiksza (i ktry kierunek zczenia jest bardziej stromy) poprzez umieszczenie wyej
wza z wikszym wspczynnikiem zczenia z tabel nadrzdn. Wze z wikszym
wspczynnikiem zczenia z tabel nadrzdn reprezentuje tabel zawierajc wicej
wierszy w tym [zero lub jeden]-do-[zero lub jeden] zczeniu.
Rysunek 7.21. Rne moliwe diagramy dla zczenia [zero lub jeden]-do-[zero lub jeden] gwnych tabeli
szczegw
Rysunek 7.22 pokazuje przypadek podobny do tego z rysunku 7.21, ale z wzami bdcymi
dokadnie w relacji jeden-do-jednego (tabel, ktre zawsze si cz). Ponownie moemy
wzmocni rwno obu kierunkw zczenia poprzez uoenie wzw w poziomie.
Ewentualnie, moemy wybra kierunek, ktry pozwala na stworzenie lepiej zbalansowanego drzewa, tj. takiego, ktre lepiej mieci si na stronie, umieszczajc wzy z bardziej
rozbudowanymi gaziami wyej. To, ktre rozwizanie wybierzemy, ma mniejsze znaczenie, jeli tylko pamitamy, e oba kierunki s w zasadzie skierowane ku doowi, niezalenie od tego jak s przedstawione na diagramie.
Rysunek 7.22. Rne moliwoci przedstawienia diagramu dla gwnych tabel szczegw zczonych
dokadnie jeden-do-jednego
248
Zczenia zewntrzne
Niemal zawsze sensem i celem zczenia zewntrznego jest zapobieenie utracie podanych danych z tabeli, z ktrej wychodzi zczenie. Nieprawidowe zczenia zewntrzne,
ktre opisz w nastpnych podrozdziaach, oglnie rzecz biorc, pokazuj pewne sprzecznoci z podanymi powyej przyczynami istnienia zcze zewntrznych.
Nawet warunki takie, jak T2.Unpaid_Flag != 'T' lub NOT T2.Unpaid_Flag = 'Y',
ktre powinny by prawdziwe, w zewntrznym przypadku nie s.
W przypadku warunkw w klauzuli WHERE, baza danych interpretuje wartoci
null w mao intuicyjny sposb. Jeli patrzymy na null jako na reprezentacj
wartoci niewiadoma w odniesieniu do kolumny tabeli, a nie w bardziej standardowym znaczeniu nie ma zastosowania, moemy zacz rozumie jak
baza danych traktuje wartoci null w klauzuli WHERE. Za wyjtkiem pytania
konkretnie o to, czy kolumna ma warto null, niemal kade pytanie jakie mona
zada, zwrci rezultat nieznany, co w istocie jest prawdziw wartoci wikszoci
warunkw z wartociami null. W razie odrzucenia wierszy zapytania, baza danych
traktuje prawdziw warto nieznany jak FALSE, nie przyjmujc wierszy z nieznanymi prawdziwymi wartociami w klauzuli WHERE. I o ile NOT FALSE =
TRUE, okazuje si, e NOT "nieznane" = "nieznane"!
249
Wedug nowszej notacji ANSI, ktra jest jedyn dozwolon w DB2, warunek filtrowania przenosi si z klauzuli FROM i staje si jawnym warunkiem zczenia:
FROM ... Orders O ...
LEFT OUTER JOIN Code_Translations OTypeTrans
ON O.Order_Type_Code=OTypeTrans.Code
AND OTypeTrans.Code_Type='TYP_ZAMOWIENIA'
250
O co tak naprawd zapytanie pyta baz danych? Semantycznie jest to danie o dwa, raczej
rne, zbiory wierszy zbir wszystkich pracownikw, ktrzy nie maj adnych oddziaw i zbir wszystkich pracownikw, ktrych menaderowie nie maj departamentw.
Moliwe jest, e aplikacja rzeczywicie potrzebuje dwch takich niezalenych zbiorw
jednoczenie, aczkolwiek wydaje si bardziej prawdopodobnym, e programista nie zauway, e tak proste zapytanie zwraca tak zoone rezultaty, i wcale nie potrzebowa
jednego z tych zbiorw.
Rozwamy nieco inny przykad:
SELECT ... FROM Employees E
LEFT OUTER JOIN Departments D
ON E.Department_ID=D.Department_ID
WHERE D.Department_ID IS NULL
Na pierwszy rzut oka zapytanie to moe si wydawa dziwne, poniewa klucz gwny
(Department_ID) tabeli Department nie moe by rwny null. Pomimo tego, taki klucz
wartoci null nie mgby nigdy zczy si z adn inn tabel zczeniem takim, jak
zaprezentowane (poniewa warunek NULL = NULL zwraca warto nieznany). Jednake, poniewa jest to zczenie zewntrzne, istnieje sensowna interpretacja tego zapytania:
Znajd pracownikw, ktrzy nie maj przypisanych departamentw. W zewntrznej
czci tego zewntrznego zapytania, kada kolumna tabeli Departments, wczajc
nawet obligatoryjne rne od null kolumny, jest zamieniana na null. Dlatego warunek D.Department_ID IS NULL jest prawdziwy jedynie w zewntrznym przypadku. Istnieje
jednak znacznie popularniejszy i atwiejszy do odczytania sposb wyraenia tego zapytania:
SELECT ...
FROM Employees E
WHERE NOT EXISTS (SELECT *
FROM Departments D
WHERE E.Department_ID=D.Department_ID)
Chocia forma NOT EXISTS w tego typu zapytaniu jest bardziej naturalna, atwiejsza do
odczytania i zrozumienia, forma pierwsza (najlepiej jeli jest otoczona przez odpowiednie komentarze) ma swoje miejsce w optymalizacji SQL. Przewaga wyraenia NOT
EXISTS jako zczenia zewntrznego, po ktrym wystpuje wyraenie Klucz_Gwny IS
NULL, polega na tym, e daje ono wiksz kontrol w momencie wystpienia zczenia
251
Jednake rezultat nie bdzie taki, jakiego bymy sobie yczyli! Przypomnijmy, e
SQL Server interpretuje wszystkie warunki filtrowania na tabeli zczonej zewntrznie jako cz zczenia i bdzie prbowa utworzy poczenie z tabel
Departments, ktra ma wartoci null klucza gwnego (wartoci null w kolumnie D.Department_ID). Nawet jeli takie wiersze istniej z naruszeniem poprawnego
projektu bazy danych, nigdy nie zcz si poprawnie z tablic Employees, poniewa warunek rwnoci nie moe by prawdziwy dla wartoci null klucza.
Zamiast tego zapytanie nie przefiltruje adnych wierszy, zwracajc wszystkich
pracownikw z wszystkimi zczeniami wpadajcymi w przypadek zewntrzny.
Powysze zczenie w starej wersji bazy danych Oracle miaoby nastpujcy zapis:
SELECT ...
FROM Table1 T1, Table3 T2, Table3 T3
WHERE T1.FKey2=T2.PKey2(+)
AND T2.FKey3=T3.PKey3
252
O co pyta kade z tych zapyta? Istot pytania mona by sformuowa w mniej wicej taki
sposb: Podaj mi informacje dotyczce wszystkich pracownikw, ktrzy maj departamenty (przypadek wewntrzny) wraz z danymi ich departamentw, a take informacje
253
254
Zapytania z podzapytaniami
Niemal wszystkie prawdziwe zapytania z podzapytaniami nakadaj specjalny rodzaj
warunku na wiersze w zewntrznym, gwnym zapytaniu musz pasowa albo te
nie do odpowiednich wierszy powizanego zapytania. Na przykad, jeli potrzebujemy
danych odnonie departamentw, ktre maj pracownikw, zapytanie mogoby wyglda nastpujco:
SELECT ...
FROM Departments D
WHERE EXISTS (SELECT NULL
FROM Employees E
WHERE E.Department_ID=D.Department_ID)
Zczenie E.Department_ID=D.Department_ID w kadym z tych zapyta jest zczeniem skorelowanym, ktre dopasowuje do siebie tabele zapytania zewntrznego i podzapytania. Zapytanie EXISTS ma alternatywn, rwnowan posta:
SELECT ...
FROM Departments D
WHERE D.Department_ID IN (SELECT E.Department_ID FROM Employees E)
Zapytania z podzapytaniami
255
Dla zcze skorelowanych (znanych jako zczenia typu semi-join, jeli odnosz si do
podzapyta typu EXISTS) z tabeli Departments do Employees, diagram rozpoczyna si
z takimi samymi statystykami zczenia, jak pokazano na rysunku 5.1.
Jak kade inne zczenie, zczenie typu semi-join, ktre czy zapytanie wewntrzne
z zewntrznym jest przedstawione w postaci strzaki na jednym z kocw poczenia,
wskazujcej na klucz gwny. Podobnie na kadym kocu znajduj si wspczynniki
zczenia, ktre reprezentuj te same waciwoci, ktre zczenie to miaoby w zwykym
zapytaniu. Uywam strzaki poredniej, aby wskaza przejcie od wza zewntrznego
zapytania skorelowanego do wza podzapytania. Umieciem E obok strzaki poredniej,
aby pokaza, e jest to zczenie typu semi-join dla elementu EXISTS lub IN podzapytania.
256
W tym przypadku, tak jak w wielu przypadkach podzapyta, cz diagramu z podzapytaniem jest pojedynczym wzem reprezentujcym podzapytanie bez jego wasnych
zcze. Rzadziej, jednak podobnie jak w tym przykadzie, zapytanie zewntrzne jest
pojedynczym wzem, reprezentujcym to zapytanie bez zcze wasnych. Skadnia jest
zasadniczo nieograniczona, z moliwoci wystpienia wielu podzapyta zczonych
z zapytaniem zewntrznym lub te podzapyta ze zoon wewntrzn struktur zcze lub nawet podzapyta wskazujcych na gbiej zagniedone w nich samych
podzapytania.
Zczenie typu semi-join wymaga take do dwch liczb, aby pokaza waciwoci
podzapytania, dziki czemu mona wybra najlepszy plan. Rysunek 7.27 pokazuje obie
te wartoci, ktre czasem s niezbdne do wybrania optymalnego planu radzenia sobie
z podzapytaniem.
Pierwsza warto, tu obok E (rwna 20 na rysunku 7.27) jest wspczynnikiem korelacji.
Wspczynnik korelacji jest wspczynnikiem I/E. E jest szacunkowym lub zmierzonym
czasem wykonania najlepszego planu prowadzcego z zapytania zewntrznego do podzapytania (podajc za logik zapytania EXISTS). I jest szacunkowym lub zmierzonym
czasem wykonania najlepszego planu prowadzcego z zapytania wewntrznego do
zapytania zewntrznego (podajc za logik zapytania typu IN). Moemy zawsze wyznaczy ten wspczynnik bezporednio poprzez zmierzenie czasu wykonania obu form,
co zazwyczaj jest do atw czynnoci, chyba e mamy do czynienia z du liczb
poczonych podzapyta. W dalszej czci ksizki opisz kilka regu pomocnych
w oszacowaniu wartoci I/E mniej lub bardziej celnie, ale nawet przybliona estymacja
jest wystarczajca do wyboru planu, kiedy jak ma to czsto miejsce warto jest
bd znacznie mniejsza, bd znacznie wiksza ni 1,0. Kiedy wspczynnik korelacji
jest wikszy ni 1,0, naley wybra podzapytanie skorelowane z warunkiem EXISTS
oraz plan, ktry wychodzi od zapytania zewntrznego do podzapytania.
Nastpn now wartoci jest skorygowany wspczynnik filtrowania podzapytania (rwny
0,8 na rysunku 7.27) zaraz obok wspczynnika zczenia detali. Jest to szacunkowa
warto, ktra jest pomocna w wyborze najlepszego miejsca w porzdku zczenia do
sprawdzenia warunku podzapytania. Ma ona jedynie zastosowanie do zapyta, ktre
zaczynaj si od zapytania zewntrznego, tak wic naley j wykluczy z kadego zczenia typu semi-join (ze wspczynnikiem korelacji mniejszym ni 1,0), ktre moe by
zamienione na rdowe zapytanie w planie wykonania.
Jeli mamy wicej ni jedno zczenie typu semi-join ze wspczynnikiem korelacji
mniejszym ni 1,0, powinnimy wyj od podzapytania o najmniejszym wspczynniku korelacji, ale wci bd nam potrzebne skorygowane wspczynniki filtrowania
pozostaych podzapyta.
Zanim wyjani, jak obliczy wspczynnik korelacji i skorygowany wspczynnik korelacji podzapytania, zastanwmy si, kiedy bdziemy ich potrzebowa. Rysunek 7.28
pokazuje cz diagramu zapytania dla podzapytania typu EXISTS ze rdow tabel
szczegw na kocu zczenia typu semi-join odpowiadajcemu kluczowi gwnemu.
Zapytania z podzapytaniami
257
Zczenie semi-join na rysunku nie rni si funkcjonalnie od zwykego zczenia, poniewa zapytanie nigdy nie znajdzie wicej ni jednego pasujcego wiersza z tabeli M dla
dowolnego wiersza zapytania zewntrznego.
Zakadam tutaj, e cae poddrzewo poniej M ma form normaln (ze wszystkimi poczeniami wskazujcymi ku doowi na klucze gwne), tak e cae podzapytanie mapuje
si jeden-do-jednego z wierszami ze rdowej tabeli szczegw M tego poddrzewa.
258
Rysunek 7.29. Zoony przykad zczenia semi-join skorelowanego z kluczem gwnym rdowej tabeli
szczegw podzapytania
Aby transformacja z jednej formy w drug staa si oczywista, zrobiem odpowiednie wcicia
w kodzie. Diagram zapytania jest niemal identyczny, jak mona zobaczy na rysunku 7.30.
Ta nowa forma ma duy stopie dodatkowej swobody, pozwalajc na przykad na plan,
ktry czy rednio filtrowany wze P tu po zczeniu z wysoce filtrowanym wzem O,
ale przed zczeniem z niemal nieprzefiltrowanym wzem OT. W oryginalnej formie baza
danych byaby zmuszona do wykonania caego podzapytania, zanim mogaby rozway
zczenia z wzami zapytania zewntrznego. Poniewa w przypadkach takich jak ten
Zapytania z podzapytaniami
259
260
Dlatego jeli zczenie semi-join jest skierowane ku grze, nie powinno si zamienia
zcze tego typu na zwyke zczenia, za wyjtkiem sytuacji, gdy wspczynnik zczenia szczegw dla zczenia semi-join jest bliski 1,0 lub nawet nieco mniejszy.
Aby dokoczy tworzenie diagramu podzapytania typu EXISTS, musimy mie kilka regu pozwalajcych nam oszacowa wspczynnik korelacji oraz skorygowany wspczynnik filtrowania podzapytania. W oszacowaniu wspczynnika korelacji moe nam
pomc opisana poniej procedura.
1. Dla zczenia typu semi-join, niech D bdzie wspczynnikiem zczenia
szczegw, M wspczynnikiem zczenia tabeli nadrzdnej. Niech S bdzie
najlepszym (najmniejszym) wspczynnikiem filtrowania spord wszystkich
wzw podzapytania oraz niech R bdzie najlepszym (najmniejszym)
wspczynnikiem filtrowania wszystkich wzw zapytania zewntrznego.
2. Jeli DS < MR to wspczynnik korelacji bdzie rwny (DS)/(MR).
3. Natomiast jeli S > R, wspczynnik korelacji bdzie rwny S/R.
4. W przeciwnym wypadku, niech E bdzie zmierzonym czasem wykonania
najlepszego planu, ktry wiedzie od zapytania zewntrznego do podzapytania
(podajc za logik dziaania EXISTS). Niech I bdzie zmierzonym czasem
wykonania najlepszego planu prowadzcego z zapytania wewntrznego
do zewntrznego (w zgodzie z logik IN). Wwczas wspczynnik korelacji bdzie
rwny I/E. Jeli krok 2. lub 3. pozwoli nam znale przybliony wspczynnik
korelacji, moemy cakiem bezpiecznie okreli, w ktrym kierunku poprowadzi
podzapytanie bez mierzenia czasw wykonania.
Szacunkowa warto uzyskana w kroku 2. i 3. moe nie by tak celna, jak bezporednie zmierzenie czasu wykonania. Jednak szacowanie jest wystarczajce, jeli
tylko dokonywane jest ostronie, tak aby unikn wartoci prowadzcych do
niewaciwego wyboru rda zapytania zewntrznego lub podzapytania. Reguy
przedstawione w kroku 2. oraz 3. s zaprojektowane specjalnie dla przypadkw,
w ktrych takie ostrone, zachowawcze szacowania s wykonalne.
Jeli w kroku 2. lub 3. nie uda si uzyska estymacji, wartoci, ktra bdzie
najbezpieczniejsza i najatwiejsza do uzyskania jest po prostu warto zmierzona.
W takim przypadku, ktry wystpuje do rzadko, znalezienie dobrej wartoci
na podstawie oblicze byoby na tyle skomplikowane, e nie jest warte wysiku.
W momencie znalezienia wspczynnika korelacji musimy sprawdzi, czy potrzebujemy
skorygowanego wspczynnika filtrowania podzapytania i w takim przypadku sprbowa
go ustali:
1. Jeli wspczynnik korelacji jest mniejszy ni 1,0 oraz mniejszy ni wszystkie
pozostae wspczynniki korelacji (w wypadku wielu podzapyta) musimy si
zatrzyma. Wwczas nie potrzebujemy wspczynnika filtrowania podzapytania,
poniewa jest on pomocny jedynie w przypadku, gdy ustalamy, kiedy wyjdziemy
ze zczenia zewntrznego, co nie ma w tej sytuacji zastosowania.
Zapytania z podzapytaniami
261
262
Zapytania z podzapytaniami
263
Aby zamieni zapytanie NOT IN na NOT EXISTS bez zmian funkcjonalnoci, musimy
doda warunek NOT NULL na kluczu zczenia skorelowanego w tabeli zewntrznej. Dzieje si tak, poniewa warunek NOT IN jest rwnowany serii warunkw
rny-od poczonych za pomoc OR, ale wedug bazy danych warunek NULL!=
<JakasWartosc> nie jest prawdziwy, a wic forma NOT IN odrzuca wszystkie
wiersze zapytania zewntrznego dziki kluczowi skorelowanemu o wartoci null.
Ten fakt nie jest powszechnie znany, wic moliwe jest, e prawdziw intencj
twrcy takiego zapytania byo wczenie w rezultat zapytania tych wierszy, ktre
forma NOT IN odrzuca. Po zamianie form mamy dobr okazj, aby wyszuka i naprawi tego typu bdy.
Oba warunki podzapytania, typu EXISTS i NOT EXISTS, zaprzestaj poszukiwa pasujcych wierszy tu po znalezieniu pierwszego dopasowania, jeli tyko takie istnieje.
Warunki podzapyta typu NOT EXISTS s potencjalnie bardziej pomocne we wczesnych
fazach planu wykonania, poniewa kiedy odpowiednie wiersze znalezione s wczenie,
zapytanie odrzucajc je sprawia, e pniejsze kroki planu wykonania odbywaj si
szybciej. W przypadku warunku EXISTS, baza danych musi sprawdzi kad moliwo
pasujcych do siebie wierszy, po czym wszystkie je odrzuca, co jest duo kosztowniejsz
operacj, gdy istnieje wiele szczegw na wiersz nadrzdny, zczone przez zczenie
semi-join. Zapamitajmy nastpujce reguy, ktre porwnuj warunki EXISTS i NOT
EXISTS wskazujce na tabele detali z nadrzdnej tabeli zapytania zewntrznego:
Nieselektywny warunek EXISTS nie jest kosztowny przy testowaniu
(poniewa atwo znajduje dopasowanie, zazwyczaj na pierwszym wierszu
zczonym przez semi-join), ale odrzuca niewiele wierszy z zapytania
zewntrznego. Im wicej wierszy zwrcioby izolowane podzapytanie,
tym mniej kosztowny i selektywny jest warunek EXISTS. Warunek EXISTS,
ktry cechowaby si du selektywnoci, byby take kosztowny w sprawdzaniu,
gdy musi on odrzuci dopasowanie na kadym wierszu szczegw.
Selektywny warunek NOT EXISTS nie jest kosztowny przy sprawdzaniu
(poniewa atwo znajduje dopasowania, zazwyczaj ju na pierwszym wierszu
zczonym przez semi-join) i odrzuca wiele wierszy z zapytania zewntrznego.
Im wicej wierszy zwrcioby izolowane podzapytanie tym mniej kosztowny
i bardziej selektywny jest warunek EXISTS. Z drugiej strony, mao selektywne
warunki NOT EXISTS s kosztowne w sprawdzaniu, gdy musz potwierdzi
brak dopasowania dla kadego wiersza szczegw.
264
Zapytania z podzapytaniami
265
4. Jeli wszystkie wspczynniki korelacji s wiksze lub rwne 1,0 lub jeli warunki
podzapytania s jedynie typu NOT EXISTS, tabel rdow wybieramy z zapytania
zewntrznego, tak jakby zapytanie to nie miao adnych warunkw podzapytania,
zgodnie ze zwykymi reguami odnoszcymi si do prostych zapyta.
5. W momencie osignicia wzw zapytania zewntrznego, ktre zawiera
zczenia semi-join lub anti-join z jeszcze niewykonanymi podzapytaniami,
cae podzapytanie naley traktowa, jakby byo ono pojedynczym, podczonym
od dou wzem (nawet jeli zczenie skorelowane jest w rzeczywistoci grne).
Przy wyborze momentu wykonania pozostaych podzapyta powinno si przyj,
e ten wirtualny wze ma wspczynnik filtrowania rwny skorygowanemu
wspczynnikowi filtrowania podzapytania.
Poniewa podzapytania skorelowane zatrzymuj si na pierwszym pasujcym wierszu
jeli takowy istnieje zapobiegaj ryzyku rozmnoenia wierszy, charakterystycznego dla normalnych zcze grnych, i mog zmniejszy liczb wierszy bdcych
w obiegu. Jednak poniewa czsto zachodzi konieczno sprawdzenia wielu
wierszy, aby uzyska taki efekt filtrowania, prawdziwa warto skorygowanego
wspczynnika filtrowania podzapytania czyni ten wirtualny wze rwnowany
wzowi niemal nieprzefiltrowanemu (jeli rozpatruje si wspczynnik zysku
do kosztu).
266
Poniewa zczenie skorelowane jest typu EXISTS, krok 1. nie ma tu zastosowania. Podobnie, poniewa strzaka porednia zczenia semi-join jest skierowana ku grze, krok 2.
take nie ma tu racji bytu. Najniszy (jedyny) wspczynnik korelacji jest rwny 1,5
(tu obok E), tak wic i krok 3. nie mona tu zrealizowa. Przechodzc do kroku 4.,
znajdujemy, e najlepszym wzem rdowym zapytania zewntrznego jest M. W kroku
5. wybieramy pomidzy zczeniami dolnymi z A1 i A2, ze wspczynnikami filtrowania
rwnymi odpowiednio 0,2 i 0,7, a zczeniem dolnym z wirtualnym wzem reprezentujcym cae podzapytanie, o wirtualnym wspczynniku filtrowania rwnym 0,6.
A1 jest najlepszym spord tych trzech kandydatw, poniewa ma najodpowiedniejszy
wspczynnik filtrowania, a wic czymy si z nim w nastpnej kolejnoci. Poniewa nie
osigniemy adnego wza idc ku doowi od A1, nastpnym kandydatem do zczenia jest
podzapytanie (wykorzystujc krok 5.), a wic wykonujemy zczenie semi-join z wzem D.
Stosujc si do kroku 6. procedury (gdy rozpoczlimy podzapytanie), musimy dalej
poda t ciek, wychodzc od D jako od wza rdowego. Wykorzystujc w obrbie tego podzapytania reguy dla prostych zapyta, czymy si z S1, S3, S2 i S4, w tym
porzdku. Wracamy do zapytania zewntrznego, stosujc reguy dla prostych zapyta
i znajdujemy pozostay porzdek zczenia A2, B1, B2. Zatem cay, optymalny plan
zczenia, uwzgldniajc zczenia semi-join, ma posta (M, A1, D, S1, S3, S2, S4,
A2, B1, B2).
Zapytania z widokami
267
Zapytania z widokami
Widok moe spowodowa, e dowolnie skomplikowane zapytanie bdzie wygldao jak
prosta tabela, z punktu widzenia osoby piszcej zapytanie wykorzystujce ten widok.
Kiedy wiele zapyta wspdzieli jak cz planu wykonania SQL, wspdzielone widoki
wielokrotnego uytku mog by bardzo silnym mechanizmem redukujcym zoono
kodu aplikacji. Niestety, ukrywanie pewnych dziaa przed okiem programisty nie
zmniejsza skomplikowania krokw niezbdnych do osignicia rzeczywistych danych.
Z drugiej strony, ukrywanie zoonoci przed programist najprawdopodobniej nie
zwikszy trudnoci problemu, ktry optymalizator, czy to automat, czy te czowiek,
musi pokona, aby znale szybki plan wykonania. W dyskusji tej odnosi si bd do
dwch zapyta wanych dla problemu optymalizacji. S to zatem:
Zapytania tworzce widoki
Zapytania, ktre stanowi podstaw dla widokw (zapytania uywane do tworzenia widokw za pomoc CREATE VIEW <NazwaWidoku> AS <ZapytanieDefiniujaceWidok>).
Zapytania wykorzystujce widoki
S to zapytania, ktre naley optymalizowa i ktre s wykonywane przez baz danych. Odwouj si one do widokw w klauzuli FROM (na przykad SELECT ... FROM
Widok1 V1, Widok2 V2, ... WHERE ...).
Czsto jestem proszony o optymalizacj lub oszacowanie wydajnoci zapytania
definiujcego widok bez listy zapyta z niego korzystajcych. Nierzadko te prosi
si mnie o optymalizacj zapyta wykorzystujcych widoki bez wiedzy odnonie
zapyta tworzcych widoki. adna z prb nie jest moliwa do spenienia adne zapytanie definiujce widok, ktre jest bardziej skomplikowane ni SELECT
<ListaProstychKolumn> FROM <PojedynczaTabela>, nie zadziaa dobrze
w kadym moliwym zapytaniu wykorzystujcym ten widok. Podobnie, adne
zapytanie wykorzystujce jaki widok nie zadziaa poprawnie, jeli zapytanie tworzce widok koliduje z wydajn drog do osignicia potrzebnych danych.
Dla danego widoku musimy zna i zoptymalizowa kade zapytanie wykorzystujce
ten widok, abymy mogli powiedzie, e zapytanie je definiujce jest w tym kontekcie cakowicie poprawne. Analogicznie, musimy zna zapytanie definiujce
kady uyty widok, abymy mogli stwierdzi, czy zapytanie wykorzystujce te
widoki jest poprawne.
268
Zapytania z widokami
269
270
Przechodzc do kroku 2. procedury, tworzymy pocztkowy diagram zapytania, traktujc widoki jak zwyke tabele, w taki sposb, jak na rysunku 7.34.
Zapytania z widokami
271
Graficzny rezultat naszego przykadu powinien wyglda jak na rysunku 7.35, na ktrym
dodaem gwiazdk do umieszczonego najbardziej na lewo wza C, aby podkreli rnic
pomidzy dwoma tak samo oznaczonymi wzami. Ponownie statystyki dla filtra na wle
klienta zapoyczyem z przykadu pokazanego wczeniej na rysunku 5.5, uzyskujc w ten
sposb wspczynnik 0,0002 tu obok C w najbardziej na prawo wysunitym szkielecie.
Te czynnoci pozwalaj nam ukoczy diagram, ktrego utworzenie jest niezbdne, aby
kontynuowa optymalizacj zapytania wykorzystujcego widok, tak bymy mogli zadecydowa, czy do otrzymania optymalnego planu konieczne s zmiany w zapytaniu
definiujcym widok, czy te w zapytaniu wykorzystujcym widok.
272
Niektre widoki odnosz si do dokadnie tych samych wierszy, tej samej tabeli,
co jaka inna tabela w zapytaniu wykorzystujcym te widoki, czego rezultatem
jest wykonywanie zbytecznej pracy przez baz danych (efekt, ktry powinnimy
usun). Taki przypadek wystpuje na diagramie 7.35 dla wzw C* oraz C.
Problemem tym zajmiemy si rwnie dalszym fragmencie tej publikacji.
Zalet widokw, z perspektywy tworzenia oprogramowania jest to, e ukrywaj
zoono problemu, ale niestety dokadnie ta zaleta sprawia, e tworzenie
nadmiarowych zcze jest bardzo atwe. Przy wykorzystaniu jedynie zwykych
tabel sytuacja taka byaby atwa do zauwaenia i wymagaaby duo wicej pracy,
gdybymy chcieli j ponowi.
Wzy znajdujce si w obrbie zapytania definiujcego widok oraz zczenia
do nich prowadzce s czsto zbyteczne w uzyskiwaniu rezultatw zapytania,
ktre wykorzystuje ten widok.
Uywanie widokw ogranicza nasz kontrol nad planem wykonania.
Jeli zmienimy zapytanie definiujce widok, tak aby poprawi plan wykonania
zapytania wykorzystujcego ten widok, moemy przez przypadek obniy
wydajno innych zapyta go wykorzystujcych. Zawsze moemy utworzy
nowy widok do uycia tylko w obrbie jednego zapytania, ale powoduje
to zaprzepaszczenie korzyci pyncych z moliwoci wspdzielenia widokw.
Oglnie rzecz biorc wskazwki SQL oraz inne zmiany w zapytaniu
wykorzystujcym widoki nie wpywaj na sposb w jaki baza danych uzyskuje
dostp do tabel tego zapytania. Czasem, aby otrzyma wydajny plan wykonania,
niezbdne jest usunicie widokw.
Zapytania z widokami
273
widok i bdzie traktowa rezultat jakby pochodzi z rzeczywistej tabeli. Dla zcze
zewntrznych z widokami, baza danych wykorzystuje zazwyczaj do poczenia z t
tymczasow tabel zczenie sortujco-scalajce lub mieszajce. Takie dziaanie jest zazwyczaj bezpieczne, gdy chodzi o funkcjonalno, ale dla wydajnoci jest nierzadko
katastrofalna w skutkach, chyba e zapytanie definiujce widok jest szybkie jako zapytanie samodzielne.
Jako generaln regu dla utrzymania wydajnoci warto przyj, i naley unika
zcze zewntrznych z kadym widokiem, ktry jest bardziej skomplikowany
ni proste SELECT <ListaProstychKolumn> FROM <PojedynczaTabela>.
Podobne problemy wystpuj w przypadku wszystkich zcze z widokami, ktre zawieraj UNION lub GROUP BY w zapytaniu definiujcym widok. Chocia trzeba przyzna,
i zczenia wychodzce od takich widokw zazwyczaj dziaaj dobrze, pod warunkiem,
e zawieraj tabel, ktr wybralibymy jako rdow tabel zapytania.
Przeanalizujmy ponownie zapytanie wykorzystujce widoki z poprzedniego podrozdziau.
Jeli wczymy zapytanie definiujce widok Shipment_V do zapytania wykorzystujcego
widok w celu rozwizania problemw wydajnociowych zwizanych ze zczeniem zewntrznym, moemy spodziewa si nastpujcych rezultatw:
SELECT OV.Customer_Main_Phone, C.Honorific, OV.Customer_First_Name,
OV.Customer_Main_Phone, C.Suffix, OV.Customer_Address_ID,
A.Address_ID Shipment_Address_ID,
A.Street_Addr_Line1 Shipment_Street_Address_Line1,
A.Street_Addr_Line2 Shipment_Street_Address_Line2,
A.City_Name Shipment_City_Name, A.State_Abbreviation Shipment_State,
A.ZIP_Code Shipment_ZIP, OD.Deferred_Ship_Date, OD.Item_Count,
ODT.Text, P.Prod_Description, S.Shipment_Date
FROM Recent_Orders_V OV, Order_Details OD, Products P, Shipments S,
Addresses A, Code_Translations ODT, Customers C
WHERE UPPER(OV.Customer_Last_Name) LIKE :last_name||'%'
AND UPPER(OV.Customer_First_Name) LIKE :first_name||'%'
AND OD.Order_ID = OV.Order_ID
AND OV.Customer_ID = C.Customer_ID
AND OD.Product_ID = P.Product_ID(+)
AND OD.Shipment_ID = S.Shipment_ID(+)
AND S.Address_ID = A.Address_ID(+)
AND OD.Status_Code = ODT.Code
AND ODT.Code_Type = 'DOKLADNY_STATUS_ZAMOWIENIA'
ORDER BY OV.Customer_ID, OD.Order_ID Desc, S.Shipment_ID, OD.Order_Detail_ID
Niestety, wynik tego zapytania nie jest dokadnie taki, jak zapytania pocztkowego, ze
wzgldu na szczeglne cechy zcze zewntrznych z widokami. W szczeglnoci zapytanie
oryginalne zwraca Shipment_Date o wartoci null za kadym razem, gdy zczenie caego widoku (wczajc w to zczenie z tabel Addresses) z tabel Order_Details nie
powiedzie si. Dlatego za kadym razem, gdy dostawa nie ma poprawnego, niepustego
Address_ID, oryginalne zapytanie zwrci dla Shipment_Date warto null pomimo tego, e zczenie z Shipments jest poprawne.
274
Z du pewnoci mona powiedzie, e to dziwne zachowanie nie byo intencj programisty i nie jest funkcjonalnie niezbdne, dlatego powysza forma najprawdopodobniej
zadziaa poprawnie, a nawet lepiej ni orygina w tym szczeglnym przypadku. Jednak jakakolwiek zmiana funkcjonalnoci dla poprawienia wydajnoci jest dziaaniem
niebezpiecznym. Dlatego przed dokonaniem zmiany, takiej jak przed chwil opisanej,
ktra wcza zapytanie definiujce widok w gwne zapytanie SQL, naley si upewni,
czy nowe zachowanie w takich kracowych przypadkach jest poprawne oraz ostrzec programistw informujc ich, e zmiana moe spowodowa, i testy zwrc inne rezultaty.
W mao prawdopodobnym przypadku, gdy oryginalne zachowanie jest naprawd potrzebne lub gdy nie chcemy zagbia si w analiz poprawnoci pierwotnego zachowania
przypadkach kracowych, mona idealnie emulowa oryginaln funkcjonalno zapytania w nastpujcy sposb:
SELECT OV.Customer_Main_Phone, C.Honorific, OV.Customer_First_Name,
OV.Customer_Main_Phone, C.Suffix, OV.Customer_Address_ID,
A.Address_ID Shipment_Address_ID,
A.Street_Addr_Line1 Shipment_Street_Address_Line1,
A.Street_Addr_Line2 Shipment_Street_Address_Line2,
A.City_Name Shipment_City_Name, A.State_Abbreviation Shipment_State,
A.ZIP_Code Shipment_ZIP, OD.Deferred_Ship_Date, OD.Item_Count,
ODT.Text, P.Prod_Description,
DECODE(A.Address_ID, NULL, TO_DATE(NULL),
S.Shipment_Date) Shipment_Date
FROM Recent_Orders_V OV, Order_Details OD, Products P, Shipments S,
Addresses A, Code_Translations ODT, Customers C
WHERE UPPER(OV.Customer_Last_Name) LIKE :last_name||'%'
AND UPPER(OV.Customer_First_Name) LIKE :first_name||'%'
AND OD.Order_ID = OV.Order_ID
AND OV.Customer_ID = C.Customer_ID
AND OD.Product_ID = P.Product_ID(+)
AND OD.Shipment_ID = S.Shipment_ID(+)
AND S.Address_ID = A.Address_ID(+)
AND OD.Status_Code = ODT.Code
AND ODT.Code_Type = 'DOKLADNY_STATUS_ZAMOWIENIA'
ORDER BY OV.Customer_ID, OD.Order_ID Desc,
DECODE(A.Address_ID, NULL, TO_NUMBER(NULL), S.Shipment_ID),
OD.Order_Detail_ID
Zapytania z widokami
275
276
duych zapyta lub zapyta, ktre odfiltrowuj wikszo wierszy dopiero po osigniciu
drugiego wza, dodatkowy koszt takich logicznych operacji wejcia-wyjcia moe mie
znaczenie.
Jeli programista oryginalnie pisa zapytanie do prostych tabel, ten rodzaj bdu raczej
si nie pojawi musiaby zej z waciwej sobie cieki, aby uwzgldni nadmiarowe
zczenie, a ta redundancja byaby oczywista przy przegldzie kodu. Jednak przy wykorzystaniu widokw, tego typu bdy s atwe do popenienia i dobrze ukryte.
Jak pozby si nadmiarowego zczenia z tabel Customers? Mamy trzy moliwoci:
Moemy doda nowe kolumny do listy SELECT zapytania definiujcego widok
i w zapytaniu wykorzystujcym ten widok bdziemy ich uywa zamiast kolumn
odnoszcych si do zbytecznej tabeli. Takie rozwizanie jest bezpieczne dla innych
zapyta wykorzystujcych ten sam widok, poniewa nie zmienia ono diagramu
zapytania definiujcego widok.
Wyeliminujemy zbyteczne zczenie z zapytania definiujcego widok i w zapytaniu
wykorzystujcym widok bdziemy uywa jedynie kolumn z prostych tabel.
Jednak w razie gdy istniej inne zapytania wykorzystujce ten sam widok,
mog si one odnosi do usunitych kolumn.
Nie bdziemy wykorzystywa widoku w zapytaniu, ktre go wykorzystywao,
zamieniajc go przez rwnowane, nienadmiarowe zczenia z prostymi tabelami.
277
filtr by cakowicie niepodany i niezgodny z intencj. Dlatego przed podjciem decyzji o symulowaniu pierwotnego dziaania poprzez zapytanie oparte jedynie o tabele
i eliminujce niepotrzebne zczenie, naley sprawdzi, czy to pierwotne dziaanie
byo w ogle poprawne. Jeli zamiana spowoduje nawet drobn zmian zachowania
zapytania, nawet na lepsze, naley ostrzec testerw, e testy regresyjne mog w takich
kracowych przypadkach przynie inne rezultaty.
Niektre z tych operatorw zbiorw zasuguj na chwil uwagi. Operator UNION nie tylko
czy czci wyniku, ale musi je take posortowa i odrzuci duplikaty. Ta ostatnia
czynno jest czsto niezbdna, szczeglnie jeli projekt uwzgldnia podzia na czci
gwnie, aby odrzuci powtrzenia. W bazie danych Oracle operator UNION moe by
zamieniony przez UNION ALL, jeli stwierdzimy, e powtrzenia nie s moliwe lub nie
powinny by usunite. W bazach danych nie wspierajcych UNION ALL mona przeskoczy eliminujce dziaanie przez zastpienie pojedynczego zapytania UNION dwoma lub
wiksz liczb prostych zapyta i czc rezultaty w warstwie aplikacji zamiast w bazie
danych.
Operacja INTERSECT moe zazwyczaj by z powodzeniem zamieniona przez podzapytanie
typu EXISTS poszukujcego pasujcego wiersza, ktry byby wynikiem dziaania drugiej
czci zapytania z INTERSECT. Na przykad, jeli mielibymy dwie tabele odnoszce si
do pracownikw, moglibymy poszuka rekordw pracownika wspdzielonego w nastpujcy sposb:
SELECT Employee_ID FROM Employees1
INTERSECT
SELECT Employee_ID FROM Employees2
278
jest nastpujca:
SELECT DISTINCT Employee_ID, Manager_ID
FROM Employees1 E1
WHERE EXISTS (SELECT null
FROM Employees E2
WHERE E1.Employee_ID=E2.Employee_ID
AND NVL(E1.Manager_ID,-1)=NVL(E2.Manager_ID,-1))
Rozwizalibymy wwczas to zapytanie wykorzystujc metody opisane we wczeniejszym rozdziale Zapytania z podzapytaniami.
wiczenie
279
wiczenie
Poniszy przykad przedstawiajcy nierealistycznie skomplikowane zapytanie przygotowano tak, aby Czytelnik mg sprawdzi, czy dobrze zrozumia zasady optymalizacji
zapyta z podzapytaniami. Rysunek 7.36 obrazuje zapytanie bardziej skomplikowane
i trudniejsze ni mona by spotka po roku intensywnej pracy nad optymalizacj SQL.
Osoba, ktra poradzi sobie z tym zadaniem, poradzi sobie take z atwoci z dowolnym
scenariuszem, ktre przyniesie ycie.