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 Nem klaszterezett index Klaszterezett index Nem klaszterezett index Beágyazott oszlopok 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 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
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 Visszatérve a korábbiakhoz Táblák és indexek tárolása 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 SQL lekérdezés feldolgozásának lépései Parse Build query tree Optimize query 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 Execute query Format data 17 18 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 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) 3
19 20 (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 (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 21 22 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! JOIN műveletek Relációs algebra szerint a join egyszerűen a Descartesszorzat 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) 23 24 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 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 4
25 26 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) 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 Tudomány Adatbázisok, 2. előadás, (c) 2010 Dobos László 2010.02.21. 28 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 ) 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 29 30 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) Range join 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 5
Táblából olvasás JOIN műveletek két tábla között Table scan Folyamatosan végigolvassa az egész heap-táblát. Több párhuzamos table-scan csoportosítva fut! Merge join Bármilyen JOIN művelet. A bemeneti tábláknak sorba rendezetteknek kell lenniük. Clustered index scan Clustered index seek Nonclustered index scan Ha van a táblán klaszterezett index, akkor ez a sima tablescan 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. Nested loops Hash match 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. Nonclustered index seek Egyedi sorokat olvas be, amiket az index alapján talál meg. 33 34 Aggregáltak 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 Példa: átlagolás void Accumulate(avgstatea, double v) { a.count ++; a.v += v; } void Merge(avgstate a, avgstate b) { a.count += b.count; a.v += b.v; } double Terminate(avgstatea) { 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