Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

April 3, 2008 / by Zsolt Soczó

SQL Server 2008 újdonságok 30. – Adatlapok tömörített tárolása I.

A 2008-ban az egyik leghangsúlyosabban fejlesztett scenario az adattárházak építése és kezelése.
Gondoljunk csak az insert minimál loggingolósra fejlesztésére, a szó lesz majd a star joinok bitmap filter alapú optimalizálásáról (egy későbbi bejegyzésben), a particionált adatok párhuzamos feldolgozásáról, az indexelt nézetek, amelyek táblái állhatnak particionált lábakon, a merge utasítás, ami gyors adatátlapátolást tesz lehetővé, Change Data Capture, stb. Erősen Data Warehouse szagúak a fícsörök, nemde?
No, ezen a vonalon domborít a tömörítés is. Az SQL 2005 SP2 már bevezette a vardecimal tömörített tárolását, amely nem fix hosszúságon tárolja ezeket a számokat, csak olyan hosszan, amennyi az adott példány tényleges tárolásához kell. Például a 2.23 kevesebb helyet kér, mint a 2234234.23 vagy a 3.345353535345. Változó hosszúsággal ábrázolják tehát az egyébként fix hosszúságú decimal adatot, ezzel helyet spórolnak meg. Gondolom nem kell mondanom, miért pont ezt a típust rakták be az SP2-be, azért, mert a pénzmennyiségeket ebben szoktuk tárolni (nem kettes, hanem 10-es számrendszer alapú, ezért véges tizedes törteket pontosan tud ábrázolni, szembem mondjuk a real-lel, ami 2-es számrendszer alapú).
Az SQL Server 2008 nyilván ezen a vonalon ment tovább, és már nem csak a decimalt, hanem a többi fix hosszúságú számot is tudja változó hosszal, azaz tömörítve tárolni.
Mielőtt azoban megbeszélnénk az összes tömörítése módszert, nézzük, miért is jó ez nekünk? A compression elsődleges célja a nagy táblák adatainak tömörítése, egyszerűen a HDD-k jobb kihasználása érdekében. Azonban mivel így kevesebb IO művelettel járnak a lekérdezések, a végén még lehet – de nem biztos – hogy gyorsabbak lesznek a lekérdezések. Az adatmódosítások nyilván lassulnak. Ezért elsősorban közel csak olvasható adatokra érdemes használni. Nincs dráma a módosításnál, de pár 10%-kal lassabb lehet. A backup gyorsul, hisz kevesebb adatot kell kimásolni. A backup is tud tömöríteni 2008-ban, a kettő egymástól független, és használható együtt.
Mivel tömörebbek az adatlapok, jobban kihasználható a gép memóriája cache céljára, azaz egy 2x tömörítés hasonló hatású, mintha dupla annyi ramunk lenne cache céljára. Azért ez sem elhanyagolandó adat.
Lehet tömöríteni adatot, indexet és akár egy tábla vagy index bizonyos partícióit is. Ez utóbbi nagyon jó, mert így az archív adatokat lehet tömörítve tárolni régebbi partíciókban, míg az éppen töltött adatokat tömörítés nélkül, hogy ne lassuljanak a DML műveletek.
Hogyan tömörít az SQL Server 2008? Azért azt látni kell, hogy nem lehet egy zipet vagy egy rart berakni a szerverbe, mert bár az valószínűleg nagyobb tömörítési arányt érne el, de sokkal lassabb lenne tőle a szerver. Olyan tömörítés kellett, ami elég sokat tömörít, de nem túl nagy költséggel. Biztos sokféle módszert implementáltak és teszteltek, érdekes feladat lehetett.

Egyféle technikáról bár beszéltem, a fix adatok változó hosszúságú enkódolásáról. Ez működik a számokra és a char, nchar típusra. Kívülről persze ez nem látszik, az int továbbra is 4 bytenak látszik, annak ellenére, hogy belül lehet, hogy csak 1.5 byte. Row compression néven érhető el ez a tömörítés.

Főleg szöveges adatok esetén azonban ez a módszer nem tudna nyereséget adni, maximum ostobán megszerkesztett hosszú char, nchar oszlopoknál, de van annyi eszünk, hogy változó hosszúságú adatokat Nvarchar és társaiban tárolunk. Más módszer kell a tömörítésre, ez pedig a redundancia csökkentésével működik. Az első módszer az adatok első részében levő redundanciát űzi el. Pl. az Áladár és az Álamizsna szavakban az Ála karaktereket csak egyszer írják le a lap fejlécében modjuk 1-es index-szel, és a mezőkben csak 1dár és 1mizsna lesz. Ez a column-prefix tömörítés. Ami izgalmas ebben, hogy a módszer adattípustól függetlenül működik, ha pont egy integer első 3 byte-ja azonos egy varchar szöveg első 3 karakterét reprezentáló byte-tal, akkor összevonják őket.
Update: kissé leegyszerűsítettem itt a képet, de a megértéshez ez elég. Aki pontosan szeretné látni hogy működik ez, itt nézzen szét.
A másik módszer szótár alapú, azaz ha az alma szó egy lapon 15 sorban is szerepel bármely oszlopban, akkor csak egyszer tárolják le, és a sorokba mutatókat raknak az adatszótár adott bejegyzésére. Valójában a kettő együtt működik, először a közös prefixeket emelik ki, majd megnézik a maradékot (előző példában dár, mizsna), és ha az is többször szerepel, akkor a szótárazós módszerrel tömörítik.
Persze ezek nem csak szöveges, hanem bináris adatokra is mennek, csak így könnyebb volt szemléltetni a folyamatot. Update: pontosabban és részletesebben itt.
Melyiket használjam? A row compressionnek jelentősen kisebb a költsége, ezért a gyakrabban lekérdezett vagy módosított adatokhoz ez megfelelőbb. Cserébe nem tud annyira tömöríteni.
A gyakran használt indexeket valószínűleg nem érdemes tömöríteni, csak azokat, amelyek nagyok, de ritkán használatosak.
Kis táblákra kár baszakodni bármelyik módszerrel is, csak izzítjuk vele feleslegesen a procit.
Index seek-eken nem sokat javít a tömörítés, mert egy-egy sor miatt 6-8 lapot is ki kell csomagolni, ami felesleges macera. Range seek-ekre vagy index scan-ekre már megéri.
A sys.dm_db_index_operational_stats nézet megmutatja, melyik index mennyire és milyen módon van kihasználva (ó, ha ez meg lett volna már az SQL 2000-ben!)?
A nagy adatokra, mint varchar(max) és társai NEM működik a tömörítés, hisz az előbb leírt módszerek nyilvánvalóan nem mennek nagy adatokra, ezeket inkább a hagyományos stream alapú tömörítésekkel lehet összepakolni. Mit lehet tenni, ha ezeket is tömöríteni akarjuk?
1. Az alkalmazás maga tömörít. A mai világban ez már nem nagy dolog.
2. Tömörítő CLR UDF-et írunk, azzal tömörítünk a tárolás előtt, mondjuk egy sp-ben.
3. Olyan UDT-t írunk, ami tömörítve tárol. A méretlimit feloldása miatt ez most már lehetséges.
4. FILESTREAM oszlopot használunk tömörített NTFS könyvtárban. Ez nem tömörít olyan agresszíven, de elég gyors.

Ok, rájöttünk, hogy lehet, hogy kell nekünk a tömörítés. Mielőtt bezipelnénk az univerzumot érdemes kicsit méricskélni, mit várhatunk el tőle, hisz az adatainktól nagyban függ, mekkor lesz a nyereség, ha egyáltalán lesz? Először is, a tábla induló méretét az sp_spaceused spvel lehet megkapni.
Eztán az sp_estimate_data_compression_savings tárolt eljárással ki lehet próbáltatni, hogy egy adott tábla vagy index egy adott partícióján a row vagy page compression mennyit hozna a konyhára. Az sp persze nem áll neki a 80 Exabájtos táblát betömöríteni, hanem mintavételezéssel csinál egy kis minta táblát a tempdbben, és azt csomagolgatja, majd ennek eredményét vetíti vissza az eredeti táblára.
Méricskéljünk kicsit! (Majd egy hamarosan következő részben, mert elpukkant a laptopban a vinyó, így nincs kéznél szerverem).

Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.