483M rekord gyorsan

Adott volt egy bináris log, adódott az ötlet, hogy nézzük meg, mit lehet vele kezdeni PostgreSQL-ben, lévén, hogy nagy is, sok is és jó lenne rajta mindenféle lekérdezést művelni.

Adott volt egy Java-s program, ami képes volt a bináris logokat beparseolni. Mondom, innen szinte pikk-pakk megvan a DB-be tolás. Első nekifutásra kb. 4k request/sec PreparedStatementtel a vasdarabon. Nos, ez elég harmatos.

Első ötlet: prepared statement mellőzése, Query kézzel történő építése (szerencsére dátum numerikus adat és egy pgsql enum volt csak benne) és tömbösítve 10E elem átadása. Egyből felpattant kb. 60E rekord/sec-re.

No de ez így még mindig nem elég, elvégre is van ThreadPool. Úgy, hogy valamivel több, mint egy magot eleve megettem egyéb feladatokra, egyből felpattant 179E/sec-re.

Viszont az érdekesebb része most jön a dolognak, jó lenne ezzel a táblával gyorsan dolgozni. Problémák:
- van olyan mező, ami elég kevés egyedi értéket tartalmaz (5-6)
- van olyan mező, ami szintén elég kevés, de azért több értéket tartalmaz (kb. 4000)
- van egy x-y-z koordináta (int), amiből jó lenne x-z területre, esetleg téglatestre lekérdezni. Na meg persze konkrét x-y-z értékre is.
- arról nem is beszélve, hogy van egy timestamp with time zone, ami alapján nem ártana rendezni. Eddig ráadásul eddig percenkénti finomsággal került rögzítésre, most jönne az ezredmp pontosságú. (Egyébként itt valószínűleg lehet újraépíteni az adatbázist egy-egy ezredmp-t hozzáadva a timestamphoz, különben borulni fog a sorrend az azonos TS-ek miatt, hogy legalább a sorrend megmaradjon.)
- az se lenne hátrány, ha ezt online lehetne bővíteni. Csak INSERT meg SELECT lenne.

Szóval az igazi fejvakarás csak most jön, hogy mit lehet kihozni.

Ami biztos:
- az elsőnek említett mező alapján biztosan fel lehet particionálni. A probléma az, hogy valószínűleg még így is a 70%-a egy partícióba fog kerülni.
- Van Point adattípus, ami elvileg GIST indexszel még akár jó is lehet, viszont nekünk az összes koordinátánk int, ez meg (double,double). Még épül az index, szóval meglátjuk, mire jó. :)
- Valószínűleg nem a PgSQL lesz a nyerő erre a feladatra... :)
- ...de ha már hobbizunk egyet, megnézzük mire jó.

---

Off: jól sejtem, hogy a hup MySQL backupja fél 3-kor megy? És ha igen, a MySQL még _tényleg_ ott tart 2014-ben, hogy backup alatt képtelen kiszolgálni queryket?

Hozzászólások

Elvben lehet --skip-lock-tables argumentumot kerni tole, illetve ha atraknak az egeszet InnoDB-re, akkor az egesz problema nem letezne, tekintve, hogy tranzakcionalisan menti a DB-t, de ez itten Drupal 5, valszinuleg egyaltalan nincs felkeszitve az InnoDB-re. D6 es felette mar okes az InnoDB.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. 

mysql-el a 'load data' nekem 60000/sec-el szokta tolni a "insert"-et egy nem tul combos vason.
A sima szovegfile, benne insert-ekkel, trukkozes nelkul pedig 100/sec-el

ugyhogy szerintem jobban jarsz, ha a 'load data'-hoz szukseges formatumu file-t eloallitod a progidbol, es amikor kesz, akkor egyben betolod az adatbazisba

--
Live free, or I f'ing kill you.

Biztos, hogy nem lesz gyorsabb, ha meg kulon eloallotok +1 fájlt, mert akkor meg kell varnom, mire egy becslés szerint tobb tiz gb-s textfilet leír a lemezre, majd,azt vissza, plusz bukta a parhuzamositas. Meg be kellett parseolni az eredeti fájlt, ami szinte idő. Nem figyeltem nagyon, de tobbet futott a Java, mint a pgsql. Single threaden a 60k meg igy is megvolt. Multin sztem - ha közben nem használtam volna a gepet meg masra meglett volna a 200-240k is sztem, ha ráérek lemerem meg azt is, hogy mennyi volt, mikor a pg-re vart a Java.

Bar most mar inkabb a pekerdezesek gsorsitasa a cel.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Szerintem file/szoveg feldolgozasra dobd a java-t.
perl a nyero, a memoriat is teljesen kepes kiterhelni.
Nekem perl-el szinte minden esetben IO limitalt volt az ilyen feldolgozas. Még egyetlen core-on is.
Az itt leirt esetben CPU limitaltnak latszik a dolog.

--
Live free, or I f'ing kill you.

Két apróság:
1. 483M rekord, ha nem költői túlzás, akkor kicsit sok a perlnek, ráadásul perlből adatbázist... nem mondom, még Oracle-t is lehet(ett) kezelni, de nem nevezném optimálisnak
2. Bináris állományokat említett, abban azért nincs akkora előnye a perlnek. :)

+1: csak azt nem értem, hogy miért ragaszkodik a javahoz, mikor egyébként a .NET-től van hanyattesve. :)

> +1: csak azt nem értem, hogy miért ragaszkodik a javahoz, mikor egyébként a .NET-től van hanyattesve. :)

D'uh. Hát ennek elég egyszerű oka van: aki dolgozik valahol, annak sokszor nincs lehetősége egyénileg eldönteni, hogy miben kell fejleszteni. Főleg azért, mert új projekt sokkal ritkábban indul ahhoz képest, mint ahogy a régi cuccokba kell belenyúlni. Valószínűleg a 400M+ rekord mozgatása sem l'art pour l'art történik, hanem valaminek a része.

Igazából nem munka, hanem hobbi, illetve egy kis kísérlet. Van egy Minecraft szerver (Huncraft), amihez van egy egyedi fejlesztésű plugin. Ez a plugin tartalmaz egy bináris logot, hogy ki, hol mit csinált. Mivel az MC és a plugin Java, így minden eddigi tool is az. Ez a log egyébként 2011 februárjától tegnapig tart, az időnkénti Volediteléseket, illetve egy-egy fagyáskori adatvesztéseket - percenként írta csak a logot, ezért vannak csak percenkénti timestampek - leszámítva gyakorlatilag vissza lehetne játszani az egész történetét a szervernek.

Hétvégén eldöntöttük, hogy picit ujitunk a pluginen, lesz mögé SQL, stb. Ekkor jött az ötlet, hogy vajon egy pgsql mit tud kezdeni vele, aztán for fun megy a dolog, mert az átlaghoz képest ez már mégiscsak egy "kisebb" adatmennyiség, bigdata korában sosem árt az ilyen jellegű tapasztalat, mert ki tudja mit hoz egy munkahely.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Semmi gond nem volt jelen esetben a Javaval, leszámítva, hogy a sima prepared statement a célhoz batár lassú. (Meg, hogy a nyelv egy határ szar.) Másrészt abináris loghoz kész volt a dekóder, ha nekiálltam volna újraimplementálni, csak magamat szivattam volna és elment volna plusz egy nap.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Off: megmagyarázná valaki, hogy egy prepared statementes megoldás miért lassítja (pláne ilyen mértékben) a programot? Én azt várnám, hogy gyorsabb lesz, mert nem kell folyton újra parse-olni az sql-t.
update: közben turkáltam a neten, úgy tűnik, más is látott ilyet, viszont érdemi magyarázatot nem találtam, csak olyat, hogy a pgsql szerver nem ismeri a prepared statement-eket, de ez még ha valós lehetőség, akkor sem magyarázza, hogy miért lassabb ennyivel.

on: csak találgatásképp... esetleg nosql adatbázisok egyike, ha a pgsql nem felel meg? (Mondanám rdbms-ből az oracle xe-t, de... szóval ennyire nemvagyok aljas :) )

+1 ötlet a google találatok alapján: prepared statement helyett tárolt eljárás?

Nem biztos, hogy jól értettem, de mintha a kollégánál az lett volna a különbség, hogy a prepared statement insert-tel egyesével nyomta a rekordokat az adatbázisba illetve string-ekkel összerakott egy olyan insertet, ami több rekordot rakott be egyszerre.
Ez esetben az első megoldás, hiába a parse-olás gyorsabb, sokkal nagyobb kommunikációs overhead-del rendelkezik, mint a második.

Ötletelés, hátha nem nagy hülyeségek
-A kis értékkészlettel rendelekzőkre( főleg ha ismert ;) ) reftábla és pl.int-le helyettesteni a táblában, szöveges mezőnél ugye hossz helyett 2/4/8 byte ami csökketni a rekord hosszt táblaméretet, már ha számít :)
-kordinátákat / időt elemekre bontani (az eredetit megtartava, persze ez meg helybe kerül).
-timstamp bővülés, rekordsorszámot rögzíteni és nem borul a sorrend.

1) Csak int illetve egy timestamp, és egy enum van a táblában.
2) koordináták 3 int mezőben vannak.
3) Egyszerűbb a timestampet átírni, mint plusz egy mezőt bevezetni. (Feladat szempontjából teljesen megengedett, lévén eddig a perces intervallum is bőven elég volt).

Idő szétbontása több mezőre miért jó?

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Este még megpróbáltam létrehozni egy GIST (point(x,z)) indexet, de két óra alatt nem fejezte be engem meg zavart a zúgó gép, így kilőttem a francba. Hogyan javasolnád figyelembe véve a fentebb említett use-caseket?

Másik bajom, hogy úgy néztem, nincs neki point(int,int) adattípusa.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Nem ismerem a postgrest (és a többivel se dolgoztam rég).

- van olyan mező, ami elég kevés egyedi értéket tartalmaz (5-6)
- van olyan mező, ami szintén elég kevés, de azért több értéket tartalmaz (kb. 4000)

Tud a Postgres olyat, hogy bitmap index? Ha igen, ezekre jó lehet.

- van egy x-y-z koordináta (int), amiből jó lenne x-z területre, esetleg téglatestre lekérdezni. Na meg persze konkrét x-y-z értékre is.

Most lehet, hogy félreértem, de egy sima view-t szeretnél, ami a terület illetve a térfogat értékeket kiszámolja?

- arról nem is beszélve, hogy van egy timestamp with time zone, ami alapján nem ártana rendezni. Eddig ráadásul eddig percenkénti finomsággal került rögzítésre, most jönne az ezredmp pontosságú. (Egyébként itt valószínűleg lehet újraépíteni az adatbázist egy-egy ezredmp-t hozzáadva a timestamphoz, különben borulni fog a sorrend az azonos TS-ek miatt, hogy legalább a sorrend megmaradjon.)

Ha jól értem amit írsz, van valami olyan formátumú timestamp információ, amit a postgres nem kezel (mert ha kezelné, simán rendeznél ez alapján). Ezt akár betöltéskor, akár utólag, nem lehet valami natívan kezelt formátumra konvertálni? Oracle esetén volt valami to_date vagy micsoda nevű függvény, aminek meg kellett adni a patternt, és a bejövő stringet ez alapján értelmezte és lefordította.

Azt a részt nem értem, amit az összekeveredésről írsz. Másodperc alapján rendeznél, de az egy másodpercen belüli rekordok sorrendje legyen azonos, mint a betöltési sorrend? Én úgy tudtam, ha nem rendezel valami szerint, akkor nem garantált a sorrend, tehát ha a betöltési sorrendben látod a rekordokat, az csak szerencse.
Emiatt be kéne vezetni valami új sorrend mezőt (vagy fake ezredmásodpercet, ahogy írod), és az alapján is rendezni.

- Van Point adattípus, ami elvileg GIST indexszel még akár jó is lehet, viszont nekünk az összes koordinátánk int, ez meg (double,double). Még épül az index, szóval meglátjuk, mire jó. :)

A postgres tud olyasmit, mint az Oracle domain index? Ha jól emlékszem, ebben magad írhatod meg, hogyan indexeljen, mi alapján, és addig csiszolhatod, amíg a te konkrét esetedre és igényeidnek a legjobban megfelelő nem lesz.

bitmap index: Tudtommal nem, de bitmap search-ot szoktam látni a query planok között, szóval megnézem.

"Most lehet, hogy félreértem, de egy sima view-t szeretnél, ami a terület illetve a térfogat értékeket kiszámolja?"

Félreérted: Adott x1,z1,x2,z2 (vagy (x,z) r sugarú köre/négyzete) téglalap által leírt területben található rekordokra szűrni. Itt jöhet be az, hogy lehet, hogy y értékre is szűrni kell (x-z síkban, y a magasság tengelyünk).

"Ha jól értem amit írsz, van valami olyan formátumú timestamp információ, amit a postgres nem kezel"

De kezel, csak az most sok az azonos timestamphez tartozó rekordok száma (ami a jövőben nem lenne probléma), ezeknél jó lenne a sorrendet megőrizni.

"Én úgy tudtam, ha nem rendezel valami szerint, akkor nem garantált a sorrend, tehát ha a betöltési sorrendben látod a rekordokat, az csak szerencse."

Igen, ez a baj, de ezt meg lehet oldani úgy, hogy mindig +1 ezredmp-t kap majd az azonos timestamphoz tartozó rekord.

"A postgres tud olyasmit, mint az Oracle domain index?"

Megnézem.

"Ha jól emlékszem, ebben magad írhatod meg, hogyan indexeljen, mi alapján, és addig csiszolhatod, amíg a te konkrét esetedre és igényeidnek a legjobban megfelelő nem lesz."

Na igen, legjobb lenne nekünk x-z koordináták alapján "chunkokra" felosztani. (Egyébként ez lenne a következő ötletem, hogy eszerint particionálom az adatokat.)

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Ha mar logokat parsolsz, egy konyhakesz alkalmazas nem lenne megoldas?

--
"It all keeps adding up / I think I'm cracking up / Am I just paranoid? / I'm just stoned"
/Green Day - Basket Case/