1 2 Nem klaszterezett indexek Egy táblán csak egy klaszterezett index lehet Ha más oszlop szerint is keresni akarunk, nem klaszterezett indexeket használunk A tábla mellett megjelenő adatstruktúra Egy vagy több oszlopra építhető (kulcs) Előírt rendezési sorrenddel Csak az indexelt oszlopok értékeit tartalmazza Pointer az adatokra Megkövetelhető a kulcsok egyedisége 3 4 Nem klaszterezett index Beágyazott oszlopok Klaszterezett index Nem klaszterezett index Indexeknél: Ha csak az indexelt oszlopok kellenek a query-hez, elég az index-struktúrát végigolvasni Ha más oszlop is kell, azokat külön be kell tölteni a táblából Beágyazott oszlopok: (included columns) A pointerek mellé bekerülnek a beágyazott oszlopok is Nem kelljen az adatsort külön betölteni Csak nem klaszterezett indexeknél van értelme 5 6 Indexek tulajdonságai Előnyök: Adott oszlopok szerinti keresés gyors, de csak ha a legelső indexelt oszlopra erős a megszorítás Az indexelt adatok az előírt sorrendben, szekvenciálisan olvashatóak Hátrányok: Több tárhelyet igényel (az indexelt oszlopok még egyszer tárolódnak) Beszúráskor, módosításkor, törléskor frissíteni kell Index kitöltési faktor Indexek B-fában Laponként d kulcs és d+1 pointer Ha betelik a d cella, akkor ketté kell bontani az adott lapot Kitöltési tényező (fill factor) megadja, hogy mennyire tölthető fel a lap, mielőtt a kettébontás megtörténne INSERT-ek optimalizálhatóak Tudományos adatoknál, ahol minden be van töltve, ez legyen mindig 100% vagy automatikus 1
7 8 Index statisztika Minden tábla/index párhoz statisztika A szerver automatikusan készíti Hisztogram sorok száma ismétlődő kulcsok száma ID intervallumonként Segít az index automatikus kiválasztásában Indexek tervezése Túl kevés index Kevés optimalizálási lehetőség A legtöbb query nem lesz optimális Tranzakciós problémák (dead-lock) Túl sok index Sok tárhelyet igényel Sok idő felépíteni az indexeket Az írási műveletek nagyon drágák lesznek 9 10 Táblák és indexek tárolása Visszatérve a korábbiakhoz Tábla heap vagy klaszterezett index (B-fa) tárolás: heap vagy index és row lapokon Index index lapok kulcsok és pointerekkel 11 12 Speciális lapok Lap mérete: 8 kb Row adatok számára hasznos: 8000 bájt in-page adatok Túllógó adatok tárolására: row overflow page out-of-page adatok BLOB típusú adatokra: BLOB page varbinary(max), nvarchar(max) etc. File group Több fájl gyűjteménye Lehetnek különböző méretűek Lehetnek külön lemezen is akár, sőt Párhuzamosítás: 1 programszál / fájl A táblák/indexek file grouphoz vannak rendelve Nem egyedi fájlhoz Fájlok feltöltése egyenletes a groupon belül Egy file group akárhány táblát, indexet tartalmazhat A táblák lapjai ekkor keveredhetnek Optimális eset: egyetlen tábla lapjai szekvenciálisan A BLOB oszlopok külön groupba tehetők Az indexek (ld. később) külön groupba tehetők 2
13 14 Particionált táblák A tábla kulcsértékein tartományok definiálhatók Egy adott tartomány: partíció A partíciók külön-külön rendelhetők file grouphoz A partíciók ki/be kapcsolhatók Adatbetöltésnél lesz fontos A következı órán Milyen fizikai műveleteket végez a szerver a queryk futtatásakor? Mi az egyes műveletek költsége? Mit jelent a queryoptimalizálás? Hogyan lehet queryt optimalizálni? Hogyan kell indexeket tervezni? 15 16 SQL lekérdezés feldolgozásának lépései Parse Build query tree Optimize query Execute query Format data 17 18 Minta query plan SELECT s.specobjid, s.z FROM PhotoObjAll p INNER JOIN SpecObjAll s ON p.specobjid = s.specobjid WHERE p.dered_g < 17 Table scan Adott egy heap tábla, nincs index Csak szekvenciálisan olvasható Nincsen jól definiált sorrend Tipikus query-k: SELECT * FROM t SELECT * FROM t WHERE a = 2 3
19 20 Sort Adott egy heap tábla, nincs index Csak szekvenciálisan olvasható Nincsen jól definiált sorrend Tipikus query SELECT * FROM t ORDER BY a Sorba kell rendezni az adatokat Nagy táblákra is optimalizáltan megy, de így is lassú Diszken is működik, ha a memória nem elég nagy Sort a tempdb adatbázisban történik ezt érdemes gyors háttértárra tenni (SSD) (Clustered) index scan Meg lehet-e spórolni az összes oszlop/sor beolvasását vagy a sorba rendezést? Adott egy t tábla, rajta index a c oszlopon Query-k: SELECT c FROM t WHERE c BETWEEN 5 AND 10 SELECT c FROM t ORDER BY c Az index eleve definiál egy sorrendet, ezt használjuk ki Más sorrend esetén hiába van index, mégis kell a sort Klaszterezett indexnél rögtön rendelkezésre áll a többi oszlop Nem klaszterezett indexnél ha csak a c oszlopra van szükség elég az indexet olvasni, a táblához nem is kell nyúlni 21 22 (Clustered) index seek Adott egy t tábla, rajta index a c oszlopon A c oszlop egyedi értékeket tartalmaz SELECT c FROM t WHERE c = 12 Egyetlen sor megtalálása table scan: o(n) index seek: o(log(n)) Ha c értékei nem egyediek, akkor seek helyett scan Index seek elsősorban kulcsok esetében Bookmark (key) lookup Adott egy t tábla nem klaszterezett index a c oszlopon Nem csak a c oszlopra van szükségünk SELECT * FROM t WHERE c BETWEEN 2 AND 10 A sorokat index alapján gyorsan megtaláljuk Az index csak pointereket tartalmaz Pointer (bookmark) alapján kell előszedni a többi oszlopot is pointer alatt értendő: elsődleges kulcs vagy rowid (heap táblánál) Drága művelet, random IO! 23 24 JOIN mőveletek Relációs algebra szerint a join egyszerűen a Descartes-szorzat valamilyen részhalmaza (vagyis egy reláció) CROSS JOIN: a teljes Descrates-szorzat SELECT * FROM t1 CROSS JOIN t2 INNER JOIN: csak az ON feltételnek megfelelő sorok SELECT * FROM t1 INNER JOIN t2 ON f(t1.c1, t2.c2) Outer join LEFT/RIGHT/FULL OUTER JOIN: a bal (t1) vagy a jobb (t2), vagy mindkét táblából azokat a sorokat is hozzáveszi, amikre az f() feltétel soha nem teljesül SELECT * FROM t1 LEFT OUTER JOIN t2 ON f(t1.c1, t2.c2) Ha egy táblából azt a sort vesszük, aminek nincsen párja a másikban, akkor azok az oszlopok, amik a másik táblából jönnének mindig NULL értéket vesznek fel 4
25 26 Nested loop join Adott a t1 és t2 tábla, c1 illetve c2 oszloppal SELECT * FROM t1 INNER JOIN t2 ON t1.c1 = t2.c2 Külső ciklus: olvassuk az egyik táblát Belső ciklus: olvassuk a másik táblát Ha nincsen megfelelő index, akkor a belső ciklus annyiszor lefut (és beolvassa az adatot a lemezről), ahány sora a külső táblának van A belső ciklusban használható bookmark look-up, ha van index Merge join Ha a join feltétel t1.c1 = t2.c2 alakú SELECT c1, c2 FROM t1 INNER JOIN t2 ON t1.c1 = t2.c2 Olvassuk a két táblát azonos sorrendben! A kisebbiket akár előbb gyorsan sorba is rendezhetjük A két táblát párhuzamosan, szekvenciálisan olvassuk A lehetséges párok egyszerűen meghatározhatók Idegen kulcs, elsődleges kulcs Milyen indexeket tegyünk rájuk, hogy a join gyors legyen? Ki akarjuk használni az indexek adott sorrend szerinti olvashatóságát t1 klaszterezett indexe legyen c1 szerint rendezve t2-n legyen c2 szerinti nem klaszterezett index (megj.: t2.c2 idegen kulcs, ez nem egyedi, nem biztos, hogy jó elsődleges kulcsnak) 27 28 Hash függvény h: D R, ahol D >> R R általában integer, azt mondjuk meg, hogy hány bit hosszú legyen Nem egy-egyértelmű: hash ütközés Fontos, hogy a hash függvény nagyon gyors legyen Hash tábla Ha értékek száma: 2 d Annyi lista (bucket) ahányféle hash érték lehetséges RowT** típusú vektor A listákban tetszőleges számú elem, amikhez azonos hash érték tartozik Elem megkeresése Kiszámolni a hash-t Megkeresni a megfelelő listát o(1) Végigmenni a lista elemein o(n ) 29 30 Hash match join Adott t1 tábla egy kulccsal c1-en Adott t2 tábla megfelelő kulcs nélkül c2-n, t2 elég kicsi SELECT c1, c2 FROM t1 INNER JOIN t2 ON c1 = c2 c2 értékeire számolható hash c2 soraiból építhető egy hash tábla Join végrehajtása t1-et a kulcs szerint olvassuk a hash tábla o(1) időben megadja, hogy van-e t2-ben megfelelő sok ha van megfelelő sor, akkor az ott van a hash táblában Semi- és anti-join Semi-join Csak az érdekel, hogy a másik táblában van-e megfelelő sor, de az oszlopok értékeire nincsen szükség SELECT * FROM t1 WHERE t1.id IN (SELECT t1id FROM t2) Anti-join Olyan sorokat keresünk, aminek nincsen megfelelője SELECT * FROM t1 WHERE t1.id NOT IN (SELECT t1id FROM t2) 5
31 32 Range join Táblából olvasás Ha a kulcs nem konkrét értékére, hanem egy intervallumra szűrűnk Ez is optimálisan tud futni Hierarchikus indexelési eljárásoknál lesz fontos SELECT * FROM t1 INNER JOIN t2 ON t1.id BETWEEN t2.start AND t2.end Table scan Clustered index scan Clustered index seek Nonclustered index scan Nonclustered index seek Folyamatosan végigolvassa az egész heaptáblát. Több párhuzamos table-scan csoportosítva fut! Ha van a táblán klaszterezett index, akkor ez a sima table-scan megfelelője, minden sort beolvas. Egyedi sorokat olvas be, amiket a klaszterezett index alapján talál meg. Végig olvassa a táblát egy index szerint. Ilyenkor általában maga az adat benne van az indexben. Egyedi sorokat olvas be, amiket az index alapján talál meg. 33 34 JOIN mőveletek két tábla között Aggregáltak Merge join Nested loops Hash match Bármilyen JOIN művelet. A bemeneti tábláknak sorba rendezetteknek kell lenniük. Ha a táblák nincsenek sorba rendezve, akkor egymásba ágyazott ciklusokkal megy a JOIN. Az egyik bemeneti táblából hash táblát épít, és az alapján ellenőrzi a másik tábla sorait. COUNT(*), MIN, MAX, AVG, SUM, STDEV GROUP BY, HAVING Saját aggregált függvények is írhatók Három függvényt kell implementálni: Accumulate a következő sort dolgozza fel Merge két részszámolást von össze Terminate a végső számolást végzi el Csak olyan aggregálás végezhető el, ami ezekből kirakható, mert a tábla csak egyszer olvasható végig 35 36 Példa: átlagolás void Accumulate(avgstate a, double v) { a.count ++; a.v += v; } void Merge(avgstate a, avgstate b) { a.count += b.count; a.v += b.v; } double Terminate(avgstate a) { return a.v / a.count; } GROUP BY mőveletek Ha a tábla kicsi: hash match Hash táblával, az aggregátumokat a memóriában tartja Ha a tábla nagy: stream aggregate Sorba rendezett táblát igényel a GROUP BY-ban szereplő oszlopoknak megfelelően A bejövő sorokat sorban aggregálja Nem kell az aggregátumokat a memóriában tartani 6