Managing large databases
Hogyan fekszik az adat, mibe kerül a lekérdezés, és miért a kimondatlan séma a legdrágább hiba.
The semester
Sor vagy oszlop — és miért ebből következik minden további
Az a nagy, ami nem fér a memóriába — vagy amitől a lekérdezés megszűnik interaktív lenni.
Mielőtt bármit mondanánk a technológiáról, tisztázzuk a szót. Nincs olyan sorszám, ami fölött az adat nagy lesz. Két küszöb van, és mindkettő a géptől és a feladattól függ. Az első: nem fér a memóriába. A második: a lekérdezés megszűnik interaktív lenni — tehát elindítod, és közben elmész kávézni. A második küszöb a fontosabb, mert ez öli meg az elemzést. Nem attól áll le a munka, hogy lassú, hanem attól, hogy megszakad a gondolatmenet.
Az ábra betöltése…
Rögtön az elején egy mért kép, hogy a két küszöb ne maradjon elvont. Ez ugyanaz az összegzés négy úton, ugyanazon a másfél millió soron. A leglassabb kétszázötven ezredmásodperc, a leggyorsabb hét egész öt. Egyik sem tart percekig — ezen a méreten még minden interaktív. De szorozd fel az adatot ötvenszeresére: a felső oszlop tizenkét másodperc lesz, az alsó marad fél alatt. Ott már nem ugyanaz a munka: az egyiknél gondolkodsz, a másiknál vársz.
Ugyanaz a táblázat kétféleképpen fekhet a lemezen. Sororientáltan: egy rekord mezői egymás mellett vannak, tehát egyetlen mérés kiolvasása egy helyről megy. Oszloporientáltan: egy oszlop értékei vannak egymás mellett, tehát ha csak a nedvességre van szükséged, csak azt olvasod be. Ez a kettő nem verseng: más feladatra való. A kérdés soha nem az, melyik jobb, hanem az, hogy a te munkaterhelésed melyikre hasonlít.
Egy oszlopban egyféle érték van. Az egyformaság az, amit a tömörítő ki tud használni.
Az oszlopos tárolás előnye nem csak az, hogy kevesebbet olvasol. Egy oszlopban egyféle dolog van: csupa hőmérséklet, csupa időbélyeg, csupa táblaazonosító. Az egyforma dolgok között sok az ismétlődés és kicsi a szórás, ezt pedig a tömörítő ki tudja használni. Egy soron belül viszont keverednek a típusok — szöveg, szám, dátum —, és ott nincs mit kihasználni. Ezért lesz a Parquet-fájl nemcsak gyorsabban olvasható, hanem kisebb is.
1 500 000 sor, 5 oszlop. Mérve a `w07-storage` demóval.
Ez mért szám, nem becslés. Másfél millió sor, öt oszlop. CSV-ként hatvankét egész hat megabájt, Parquet-ként tizenöt egész kilenc. Majdnem négyszeres különbség — ugyanazon az adaton, ugyanazzal a tartalommal. Amit a CSV cserébe ad: bármelyik szövegszerkesztő megnyitja. Ez valódi előny, csak nem elemzési előny.
„Táblánként mennyi az átlagos nedvesség?” — pandas, ugyanaz a másfél millió sor, öt futás legjobb ideje.
Most a lényeg. Egyetlen kérdést tettünk fel — táblánként mennyi az átlagos nedvesség —, és ugyanazzal a könyvtárral válaszoltuk meg, kétféle fájlból. Kétszázötven ezredmásodperc, illetve huszonegy. Tizenegy egész hétszeres különbség, és egyetlen dolog változott: a fájl alakja. Ez a formátum ára, tisztán.
Ugyanaz a Parquet-fájl, ugyanaz a kérdés, három olvasó.
Most ugyanaz a fájl, három olvasóval. Figyeld meg, hogy ez külön ábra, és nem az előző mellé raktam a négy oszlopot. Ha egy rajzon áll a kétszázötven és a hét egész öt, akkor a három gyors oszlop egy képpontnyi csíkká lapul, és pont az nem látszik, amiről ez a dia szól. A tengely nulláról indul, tehát a hosszt nem torzíthatom — az egyetlen becsületes megoldás a szétválasztás. És még valamit nézz meg: a polars és a duckdb között nincs érdemi különbség. Ne is keress.
| hatás | mérőszám | mi változott |
|---|---|---|
| A formátum nyeresége | 11,7× | pandas |
| CSV ÷ pandas | ||
| Parquet | ||
| A motor nyeresége ezen felül | 2,9× | pandas |
| Parquet ÷ a leggyorsabb | ||
| Együtt | 33,4× | két változtatás egyszerre |
A leglassabb és a leggyorsabb közötti harminchármas különbséget könnyű a formátum javára írni. Nem az. Két dolog változott egyszerre: a fájl alakja és a motor. Szétszedve: ugyanaz a könyvtár, ugyanaz a kérdés, csak a formátum más — tizenegy egész hétszeres. A leggyorsabb Parquet-olvasó ezen felül hoz még két egész kilencszerest, de az már nem a formátum érdeme, hanem azé, hogy a duckdb és a polars natív és többszálú. Ha valaki két változtatást végez, és egyetlen arányt hirdet, akkor nem tudja, melyik mennyit ért.
A cella betöltése…
Ez a demó teljes kimenete. Futtasd le a saját gépeden: a számok nem lesznek pontosan ugyanezek, mert más a lemezed és a processzorod, de a viszonyok ugyanezek maradnak. Ha nálad nem így jön ki, az érdekes — akkor azt kell megnézni, miben más a géped. Ez a mondat komolyan van értve: a nem egyező mérés kérdés, nem hiba.
Három név, három szerep. A CSV átadási formátum: mindenhol megnyílik, és ez az egyetlen, de valódi erénye. A Parquet tárolási formátum: oszlopos, típusos, tömörített, sémával. Az Arrow nem fájl, hanem memóriabeli elrendezés — ettől lehet egy táblát átadni két könyvtár között anélkül, hogy lemásolnád. A hallgatók fele az Arrow-t fájlformátumnak hiszi; nem az.
| eszközfajta | mire való | mire NEM |
|---|---|---|
| relációs motor (PostgreSQL, MySQL) | sok párhuzamos írás, pontos sorlekérés, tranzakció | milliárd soros összegzés: soronként dolgozik |
| oszlopos elemző motor (DuckDB, ClickHouse) | nagy összegzés, szűrés, illesztés — olvasásra hangolva | sok apró írás: nem tranzakciós tároló |
| adatkeret-könyvtár (pandas, polars) | ami elfér a memóriában: felfedezés, átalakítás | a memórián túl: ott motor kell, nem nagyobb gép |
| elosztott motor (Spark és rokonai) | ami egy gépre nem fér el, több gépen | ami elfér: a hálózati költség többet visz, mint amit hoz |
| térbeli kiterjesztés (PostGIS) | vetület, térbeli index, poligon-metszés | általános elemzés: attól még relációs motor marad |
Most nevesítsük is az eszközöket, mert a félév során találkozni fogtok velük. Öt fajta van, és a különbség nem a sebesség, hanem a FELADAT alakja. A relációs motor sok párhuzamos írásra való: ez az üzemviteli rendszer háttere. Az oszlopos motor nagy összegzésekre. Az adatkeret-könyvtár arra, ami elfér a memóriában. Az elosztott motor arra, ami egy gépre már nem fér el — és figyeld meg a jobb oldali oszlopot: ez nem a lassúság gyógyszere. A térbeli kiterjesztés pedig attól lesz külön sor, hogy a vetületkezelés és a térbeli index nem utólag pótolható.
Típus
A CSV-nek nincs sémája. Ez nem apróság, hanem a hét legdrágább mondata. Ha nincs séma, akkor minden olvasó találgat: ez a szám egész vagy tört, ez a szöveg dátum vagy azonosító, ez az üres cella hiány vagy nulla. Két különböző program két különböző választ ad, és egyik sem szól. Ezért mondjuk, hogy az adatminőségi hibák fele nem az adatban keletkezik, hanem a kimondatlan sémában.
Érdemes egyszer végignézni, mi mire épül, mert a nevek keverednek. Legalul az objektumtároló: fájlok kulcs szerint, olcsón és korlátlanul. Fölötte a fájlformátum — nálunk a Parquet, ami oszlopos és tömörít. E kettő már elég az olvasáshoz. A harmadik réteg a táblaformátum: az adja hozzá a tranzakciót, a sémafejlődést és az időutazást. És a legfelső a motor, ami mindezt lekérdezi. A gyakori félreértés az, hogy a táblaformátum új fájlformátum lenne — nem az: a fájlok Parquet maradnak, a formátum a naplót és a pillanatképeket kezeli.
Egy kollégád exportálja a méréseket CSV-be, mert „azt mindenki meg tudja nyitni”. Az elemzés hetente egyszer fut le, és minden alkalommal a teljes fájlt beolvassa, hogy két oszlopot összegezzen. Mi a legerősebb érv a formátum megváltoztatása mellett?
Egy kollégád exportálja a méréseket CSV-be, mert „azt mindenki meg tudja nyitni”. Az elemzés hetente egyszer fut le, és minden alkalommal a teljes fájlt beolvassa, hogy két oszlopot összegezzen. Mi a legerősebb érv a formátum megváltoztatása mellett?
2023
Az oszlopos formátum azt spórolja meg, hogy fölösleges oszlopot olvass. A particionálás azt, hogy fölösleges sort. Az adatot fizikailag szétbontod egy kulcs mentén — év, hónap, tábla —, és a könyvtárszerkezet maga hordozza a kulcsot. Ha a lekérdezésed a 2025-ös évre szól, a motor a többi év könyvtárát ki sem nyitja. Ez nem gyorsítás, hanem elkerülés: a legolcsóbb olvasás az, amelyik meg sem történik.
A `w07-partition` demó mérése: 1 200 000 sor, 6 év, 40 tábla. A világos oszlop a fájlonkénti költséggel együtt.
Itt a particionálás ára és haszna egy ábrán. A kérdés végig ugyanaz: mennyi a kétezerhuszonötös év átlagos nedvessége. Particionálás nélkül hat megabájtot kell végigolvasni. Év szerint particionálva egy egész négyet — négy egész háromszor kevesebbet, és ez nem gyorsítás, hanem elkerülés: a többi öt év fájlját meg sem nyitjuk. Most nézd a harmadikat. Tovább bontva tábla szerint UGYANANNYI adat olvasódik, mert a kérdés nem szűr táblára — csak most negyven fájlból.
Két tag: a beolvasott adat és a fájlköltség. A finomabb partíció az elsőt csökkenti, a másodikat növeli.
A particionálásnak van egyszerű költségmodellje, és ez megmondja, mikor megy át haszonból veszteségbe. Az első tag a beolvasott adat: annyi, amennyi a kérdéshez kellő partíciókban van. A második tag az, amiről mindenki elfelejtkezik: minden fájl megnyitása kerül valamennyit, akkor is, ha semmit nem olvasol belőle. Ha tehát finomabbra particionálsz, az első tag csökken, a második viszont NŐ — és van olyan finomság, ahol a második elviszi az első nyereségét.
A `w07-partition` demó mérése: 1,2 millió sor, hat év, negyven tábla.
C=0,23 * 6 + 1 * 0,01=1,39MB
Húzd a csúszkát, és nézd, mi mozdul.
Ha a séma nincs kimondva, attól még van — csak mindenki mást feltételez róla.
Zárjuk a blokkot azzal, amit érdemes megjegyezni belőle. A séma nem adminisztráció, hanem szerződés: kimondja, mit jelent egy oszlop, milyen típusú, és mit szabad benne. Ha nincs kimondva, attól nem szűnik meg létezni — csak mindenki mást feltételez róla. A kimondatlan séma pontosan addig működik, amíg egyetlen ember dolgozik az adaton.
A `w07-quality` demó mérése: ugyanaz az oszlop, ha a mértékegység nincs kimondva.
Íme, mit jelent az, hogy a séma akkor is létezik, ha nincs kimondva. Egyetlen oszlop, ötvenezer sor, és a valódi átlag hat egész négy tonna hektáronként. Ha a sorok három százaléka kilogrammban érkezett, és senki nem szólt, az átlag száznyilencvenkilenc egész öt lesz — háromezer százalékos eltérés. Ez kibukik, mert fizikailag lehetetlen. De ha ugyanez a három százalék tonna per HOLDBAN érkezett, akkor hat egész öt-négy-kettő jön ki: két egész két százalék eltérés. Ez nem bukik ki sehol. Az eredmény hihető marad, és ezért jut át a jelentésbe. A séma tehát nem adminisztráció: ez az egyetlen hely, ahol ezt a hibát meg lehet fogni.
Index, terv, illesztés — és miért nem a másodperc a döntés alapja
A lekérdezésterv az a lépéssorozat, ahogy a motor valóban végrehajtja a kérdést. Ki lehet íratni.
A leggyakoribb hibás reflex: lassú a lekérdezés, tehát átírjuk. Kipróbálunk egy másik illesztést, kiveszünk egy alkérdést, cserélünk valamit — és néha gyorsul, de senki nem tudja, miért. A lekérdezésterv az a lépéssorozat, ahogy a motor ténylegesen végrehajtja a kérdést. Ez nem tippelés: kiíratható, és megmondja, hol megy el az idő.
Az ábra betöltése…
Hogy ne maradjon absztrakt: ez az az ábra, amit a demó kiír. Ugyanaz a lekérdezés kétszer, nyolcszázezer soros mérési táblán. Index nélkül a terv első szava az, hogy SCAN — végigolvassa a táblát. Indexszel SEARCH, sőt COVERING INDEX, vagyis még a táblához sem kell hozzányúlnia, mert amit kérdezünk, az benne van magában az indexben. A terv tehát nem sejtés: kiíratható, két szóból megmondja az okot, és ugyanazt mondja akkor is, ha a te gépeden épp minden gyors.
A terv két szava, amit érdemes megjegyezni. A SCAN azt jelenti: a motor végigolvassa a táblát, az elejétől a végéig, és minden soron eldönti, kell-e. A SEARCH azt jelenti: van egy szerkezet, amiből tudja, hol keresse, és odaugrik. Ez a különbség nem néhány százalék: nyolcszázezer sornál a SCAN nyolcszázezer döntés, a SEARCH néhány ugrás egy fában.
A cella betöltése…
Ez a demó a saját mérése. Nyolcszázezer mérési sor, negyven tábla, egy szűrés és egy csoportosítás. Index nélkül a terv SCAN, indexszel SEARCH `USING COVERING INDEX` — és az idő ötvenhét ezredmásodpercről huszonhétre megy le. Nézd meg a terv sorát is, ne csak az időt: ott a zárójelben az is benne van, melyik oszlopon és milyen feltétellel.
Egy kétoszlopos fedő index ára ugyanazon a 800 000 soros táblán.
Itt a másik fele annak, amit az előbb mértünk. A gyorsulás két egész egyszeres — szép, de nem drámai, mert a tábla befér a gyorsítótárba. Az ár viszont mérhető: az adatbázis huszonkét egész négy megabájtról harminchét egész hatra nőtt. Tizenöt egész két megabájt, a tábla mérete hatvannyolc százaléka — egyetlen indexért, két oszlopon. És ez csak a hely; a másik ár az, hogy minden beszúrásnál karban kell tartani.
A terv az okot mondja meg, a másodperc a következményt. Az ok általánosít, a következmény nem.
Ez a blokk legfontosabb mondata, és szándékosan kellemetlen. A mért gyorsulás két egész egyszeres volt — ha ennyiből kellene dönteni, sokan azt mondanák, nem éri meg. De a tábla itt befér a memóriába. Tízszer nagyobb adaton ugyanez a SCAN már lemezről olvas, és a különbség nem kétszeres lesz, hanem nagyságrendi. A terv ezt előre megmondja; a másodperc csak azt mondja meg, mi volt ma ezen a gépen.
A `w07-queryplan` demó mérése: ugyanaz a lekérdezés, 800 000 soron.
Nézd meg a két számot, és aztán azt, mit lehet velük kezdeni. Index nélkül ötvenhat ezredmásodperc, indexszel huszonnyolc: kétszeres gyorsulás. Ez a mérés ezen a gépen, ezzel a nyolcszázezer sorral, meleg gyorsítótárral igaz. Tízszer ekkora táblán a SCAN tízszer annyi ideig tart, a SEARCH viszont alig lassul — a kétszeresből húszszoros lesz. A másodperc tehát következmény, és a nagyságrenddel változik. A terv az ok, és az nem változik: a SCAN akkor is végigolvas, ha épp gyorsan teszi.
Felveszel egy indexet, és a lekérdezés nem lesz gyorsabb. Kiíratod a tervet, és továbbra is SCAN szerepel benne. Melyik magyarázat nem lehet ok?
Felveszel egy indexet, és a lekérdezés nem lesz gyorsabb. Kiíratod a tervet, és továbbra is SCAN szerepel benne. Melyik magyarázat nem lehet ok?
A motor a becsült sorszámból választ algoritmust. Rossz becslés → rossz terv, változatlan SQL mellett.
Két tábla összekapcsolása közös kulcs mentén — ez a legtöbb elemzés első lépése, és a legtöbb rossz terv is itt születik. A motor megbecsüli, hány sor jön ki, és ebből választ algoritmust. Ha a becslés jó, a terv jó. Ha rosszul becsüli — mert a kulcs eloszlása ferde, mert az egyik tábláról nincs statisztikája —, akkor rossz algoritmust választ, és a lekérdezés egy nagyságrenddel lassabb lesz. Ilyenkor nem a SQL a hibás, hanem a statisztika elavult.
A `w07-join` demó mérése: 600 000 sor, azonos SQL, két kulcseloszlás. Egyetlen sqlite-motoron.
Ezt a mérést azért szeretem, mert az ellenkezőjét adta annak, amit vártam. Hatszázezer sor, negyven tábla, ugyanaz az illesztés kétféle kulcseloszlással. A ferde esetben egyetlen tábla viszi a sorok nyolcvan százalékát — és a lekérdezés nem lassabb lett, hanem gyorsabb: nulla egész hatvannyolcszoros idő. Egy motoron a teljes munka ugyanannyi, és a ferde esetben a találatok nagy része ugyanoda esik, ami a gyorsítótárnak kedvez.
Ugyanaz a két kulcseloszlás, 8 partícióra osztva. A szaggatott vonal az ideális 8-szoros gyorsulás.
És itt van, hol számít a ferdeség. Ha a munkát szétosztjuk — particionált táblán, több szálon, fürtön —, akkor nem az összes munka dönti el a futásidőt, hanem a leghosszabb rész. Egyenletes kulcsnál nyolc partícióra bontva a legnagyobb rész tizenkét egész öt százalék, tehát a nyolcszoros gyorsulás megvan. Ferde kulcsnál a legnagyobb rész nyolcvankét százalék: az elérhető gyorsulás egy egész kettő. Nyolc magból hét várakozik, és a SQL közben betűre ugyanaz.
A legnagyobb rész szabja meg a futásidőt. A gyorsulás felső korlátja 1 / legnagyobb rész.
Az előző dián nyolc magból hét várakozott. Ennek pontos képlete van, és ez a hét egyik legáltalánosabb tanulsága. Ha a munkát p részre osztod, a futásidő nem az átlagtól függ, hanem a LEGNAGYOBB résztől — mindenki arra vár. Az elérhető gyorsulás tehát egy per a legnagyobb rész aránya, és ez akkor is igaz, ha végtelen sok magod van. Nézd meg, mit jelent ez a mért számokon: egyenletes kulcsnál a legnagyobb rész 12,5 százalék, tehát nyolcszoros gyorsulás. Ferde kulcsnál nyolcvankettő százalék — tehát 1,2-szeres.
A `w07-join` demó két kulcsa nyolc partícióra osztva: 12,5 % és 82,0 %.
G=1 / 0,13=8×
Húzd a csúszkát, és nézd, mi mozdul.
A cella betöltése…
A cella itt fut. A csavar a ferdeség mértéke: enyhítsd nulla egész négyre a nyolcvan százalék helyett, és nézd meg, mennyi marad a párhuzamosításból. Az elérhető gyorsulás egy per a legnagyobb rész — ebből előre ki tudod számolni, mit vársz, és a mérés vagy megerősíti, vagy nem.
Két munkaterhelés, két világ. A tranzakciós — OLTP — sok apró írásból és pontkeresésből áll: a mérésrögzítő beszúr egy sort, a kezelőfelület kikeres egy rendelést. Az elemző — OLAP — ennek a fordítottja: kevés lekérdezés, de mindegyik sok sort érint. Ugyanaz az adat mindkettőben élhet, de nem ugyanabban az alakban, és ez a hét első blokkjának a következménye.
Szerver nélkül, a folyamatba ágyazva, közvetlenül a Parquet-fájlon. Ami a tranzakciósnak a SQLite, az az elemzőnek ez.
Van egy eszközosztály, ami az elmúlt években átrendezte ezt a képet. A beágyazott elemző motor — a legismertebb a duckdb — szerver nélkül, a folyamatodba ágyazva fut, és Parquet-fájlon közvetlenül tud SQL-t futtatni. Ami a tranzakciós világban a SQLite, az az elemzőben ez. Nem kell adatbázist telepíteni ahhoz, hogy SQL-lel dolgozz néhány tízmillió soron — és a mérésünkben ez volt a leggyorsabb út.
A `w07-storage` demó mérése: ugyanaz az összegzés, 1 500 000 soron, öt futás legjobbja.
Mit nyersz azzal, hogy a motort a folyamatba ágyazod. Ugyanaz a kérdés, ugyanaz a másfél millió sor, négy úton. A pandas a CSV-ről száz-ötvennyolc ezredmásodperc alatt olvas. Ugyanaz a pandas Parquet-ről tizennégy egész hat. A polars négy egész kilenc, a DuckDB négy egész öt. A két végpont között harmincötszörös különbség van — és közben egyetlen szervert sem telepítettünk, nincs adatbázis-felhasználó, nincs port. A DuckDB közvetlenül a fájlra kérdez. Ezért mondjuk, hogy ami a tranzakciósnak a SQLite, az az elemzőnek ez.
Akkor indokolt, ha folyamatos a beérkezés ÉS megőrzési szabály is kell. Pusztán attól, hogy az adat idősor, még nem.
Az utolsó tárolási fajta, amivel agrárban találkozni fogsz. Az idősor-adatbázis időbélyeg szerint particionál, erősen tömörít, és megőrzési szabályokat ismer: a nyers percenkénti adat egy hónap után óránkéssé ritkul magától. Akkor indokolt, ha folyamatosan érkező méréssorod van, és megőrzési szabály is kell hozzá. Ha csak idősorod van, de nem folyamatos a beérkezés, akkor a particionált Parquet is elég — és nem kell hozzá szolgáltatást üzemeltetni.
Az ábra betöltése…
Mielőtt idősor-adatbázist telepítenél, nézd meg ezt. Egymillió-kétszázezer sor, hat év, és a kérdés egyetlen évre szól. Particionálás nélkül hat megabájtot olvasunk be. Év szerint particionálva egy egész négyet — négy egész háromszor kevesebbet, és ez nem gyorsítás, hanem elkerülés: a többi év fájljait meg sem nyitjuk. De nézd meg a harmadik oszlopot. Év ÉS tábla szerint bontva ugyanannyi adat olvasódik, mert a kérdés nem szűr táblára — csak most negyven fájlból teszi, és a fájlonkénti nyolc kilobájt miatt egy egész kétszer drágább. A particionáló kulcs tehát nem attól jó, hogy finom, hanem attól, hogy a lekérdezéseid arra szűrnek.
| adatfajta | jellemző mérete | ahova való |
|---|---|---|
| gépadat (CAN-busz, telemetria) | napi több millió sor, időrendben | idősor-adatbázis, vagy idő szerint particionált Parquet |
| táblahatár, kezelési egység | néhány ezer poligon, ritkán változik | térbeli kiterjesztésű relációs motor (PostGIS) |
| műhold- és drónfelvétel | képenként több száz MB, sok felvétel | objektumtároló, felhőre optimalizált GeoTIFF-ként |
| laboreredmény, mintaadat | néhány ezer sor, sok metaadattal | relációs tábla — itt a séma a fontos, nem a méret |
| üzemi törzsadat (tábla, gép, dolgozó) | néhány száz sor, sokszor hivatkozva | relációs tábla, a többi réteg erre illeszt |
És most tegyük össze, hogy egy valódi agrárüzemben mi hol van. Négy forrásfajta, négy eltérő alak — és mindegyikhez más tároló való. A gépadat idősor, másodperces felbontással: idősor-adatbázisba vagy particionált Parquetbe. A táblahatár vektoros geometria: térbeli kiterjesztéssel ellátott relációs motorba. A műholdkép raszter: felhőre optimalizált GeoTIFF-ként objektumtárolóba. A laboreredmény kevés sor, sok metaadat: relációs táblába. Aki mind a négyet egyetlen technológiába akarja tenni, az háromra rossz választ ad.
Sorrend, amit érdemes megjegyezni. Először a tervet nézed meg, mert az mondja meg az okot. Aztán megnézed, mennyi adatot olvas be egyáltalán — gyakran itt derül ki, hogy oszlopot vagy partíciót lehet kihagyni. Csak ezután jön az index, és legvégül a SQL átírása. A legtöbben fordított sorrendben csinálják, és ezért nem tudják, mi segített.
A cella betöltése…
Ez a particionálási demó teljes kimenete, hogy a fájlszámot és a bájtokat együtt lásd. A sorrend, amit az előző dián felsoroltunk, itt kap számot: előbb azt nézed meg, mennyi adat olvasódik be egyáltalán, és csak utána nyúlsz indexhez vagy SQL-hez. Ebben a mérésben a partíció négy egész háromszorosát spórolta — indexet még nem is vettünk fel.
Vektor és raszter, közös koordinátarendszerben
Két alak, két világ. A vektoros adat geometria attribútumokkal: pont, vonal, sokszög — a mintavételi hely, a sorköz, a táblahatár. A raszteres adat szabályos rács, cellánként egy értékkel: ortofotó, műholdsáv, hozamtérkép. A kettő közötti váltás mindig veszteséges művelet, és ezt tudni kell előre, mert a legtöbb agrárelemzés pont ezen a határon dolgozik.
A koordináta a vetülettel és a dátummal együtt értelmes. Két réteg összevetése előbb közös rendszerbe hozás.
Ez az a hiba, amit mindenki elkövet egyszer. Két réteget összeteszel — a táblahatárt és az ortofotót —, és a tábla néhány méterrel odébb van. Nem a mérés rossz: a két réteg más vetületben van. A koordináta önmagában nem jelent semmit; csak a vetülettel és a dátummal együtt értelmes. Magyarországon ez rendszerint EOV és WGS84 keveredése, és az eltérés akkora, hogy a táblaszélen lévő sorok rossz táblához kerülnek.
Az ábra betöltése…
Egy analógia a képi oldalról, mert ott ugyanez a hiba számszerűen kimérhető. Ha a kalibrálótáblát nem a tárgy síkjába teszed, hanem öt százalékkal távolabbra, akkor a méretbecslés pontosan öt százalékkal téved — a lépték lineáris a távolsággal, tehát a referencia relatív hibája egy az egyben átmegy az eredménybe. És a kép szélén jön hozzá a második tag: a lencsetorzítás a sarokban további tíz egész öt százalékot visz el. Egy nyolcvanöt milliméteres kalász a sarokban hetvenhat milliméternek látszik. Térbeli adaton ugyanez a szerkezet: a koordináta a vetülettel és a dátummal együtt értelmes, és a hiba a szélén a legnagyobb.
A felbontás nem minőség, hanem döntés: mekkora a legkisebb dolog, amit látni akarsz.
A raszter felbontása nem minőségi jellemző, hanem döntés arról, mit akarsz látni. Tíz méteres cellával a táblán belüli foltosság látszik. Fél méteressel az egyes növénysorok. Száz méteressel csak a táblák közötti különbség. Egyik sem jobb: ha gyomfoltot keresel, a tíz méteres cella a foltot elkeni; ha regionális termésbecslést csinálsz, a fél méteres felbontás csak zajt és számlát hoz.
A `cv-resolution` demó mérése: 12 hektáros tábla két alakban, a rács eltolására átlagolva.
Ez mért szám, és a hetedik hét legfontosabb térbeli ábrája. Két tábla, pontosan ugyanakkora területtel — tizenkét hektár —, csak az alakjuk más: az egyik zömök, a másik keskeny és hosszú. Nézd meg, hogyan nő a keverékcellák aránya a cellamérettel. Tíz méternél a zömöknél öt egész nyolc százalék, a keskenynél kilenc egész kettő. Harminc méternél tizennégy és huszonöt. Ugyanaz a terület, ugyanaz a felbontás — kétszeres különbség, pusztán az alakból.
Ha egy cellába két különböző felszín esik, a visszaadott érték a kettő keveréke — és nem tartozik egyikhez sem.
Ez a raszter legfontosabb csapdája, és később a gépi látásnál visszatér. Egy cella nem tudja, hogy a valóságban két dolog van benne. A táblaszéli cella fele növény, fele földút — és amit visszaad, az a kettő keveréke. Az érték látszólag rendben van, csak nem tartozik semmihez. Egy tíz méteres cellánál a táblaszél teljes első sora ilyen; egy kis parcellánál ez a cellák jelentős hányada.
Ugyanaz a mérés: a táblaátlag hibája nyersen és egy cellányi negatív puffer után.
És itt a következménye, ugyanabból a mérésből. A függőleges tengelyen a táblaátlag hibája NDVI-egységben. Mindkét görbe lefelé megy, mert a keverékcella mindig lefelé húz — a táblán kívül alacsonyabb az NDVI. Harminc méteres cellánál a keskeny táblánál ez nulla egész nulla harmincegy. Ez nem hangzik soknak, de a szezonon belüli valódi különbségek is ilyen nagyságrendűek. A szaggatott vonal a negatív puffer után: egy cellányit befelé húzva a határt a hiba nullára megy.
Táblánkénti átlagos NDVI-t számolsz tíz méteres műholdképből, és az egyik keskeny, hosszú tábla átlaga évek óta gyanúsan alacsony. A szomszédos táblák rendben vannak. Mi a legvalószínűbb ok?
Táblánkénti átlagos NDVI-t számolsz tíz méteres műholdképből, és az egyik keskeny, hosszú tábla átlaga évek óta gyanúsan alacsony. A szomszédos táblák rendben vannak. Mi a legvalószínűbb ok?
Zárjuk a blokkot azzal, ahogy az első blokkhoz kapcsolódik. A vektoros adat táblázatos: sorok attribútumokkal, csak van egy geometria oszlopa is — tehát ugyanúgy él Parquet-ben, ugyanúgy particionálható. A raszter nem táblázat: a rá való formátumok cserép alapúak, és a cserép ugyanaz a gondolat, mint a particionálás. Ha a kép egy kis darabja kell, csak azt a cserepet olvasod be.
Amire az idő ténylegesen elmegy — és miért nem írjuk felül a nyerset
| Hiányzó érték | üres cella, jelölt hiány, hibás nulla | van-e tartományon kívüli vagy gyanúsan kerek érték |
|---|---|---|
| Duplikátum | ugyanaz a mérés kétszer rögzítve | egyedi-e a kulcs, és ha nem, mitől |
| Mértékegység-keveredés | t/ha és kg/parcella egy oszlopban | befér-e minden érték a fizikailag lehetséges tartományba |
| Időzóna és időbélyeg | helyi idő, nyári időszámítás, UTC | van-e éjszakai mérés napsütésre, ugrik-e az adat márciusban |
Négy fajta, és mindegyikhez tartozik egy ellenőrzés, amit meg lehet írni. Ez a lényeg: az adatminőség nem érzés, hanem ellenőrizhető állítások halmaza. Ha egy szabályt le tudsz írni, akkor futtatni is tudod minden betöltéskor, és akkor a hiba a betöltéskor derül ki, nem három lépéssel később.
A `w07-quality` demó mérése: 50 000 sor, a valódi átlag 6,401 t/ha. Az oszlop a táblaátlag eltérése.
Ez a dia az egész blokk tétele egyetlen ábrában. Öt tipikus adatminőségi hibát vittünk bele ugyanabba a tiszta méréssorba, külön-külön, és megnéztük, mennyivel tolják el a táblaátlagot. Nézd meg a nagyságrendeket. A kilogramm per hektáros egységkeveredés háromezer százalék. A jelölt hiány mínusz háromszáztizennégy. Ezek ordítanak — egy fél soros tartományellenőrzés mindet megfogja. És most nézd az első kettőt: nulla egész hét és két egész két százalék. Ezeket semmi nem fogja meg.
| a hiány fajtája | mit jelent | mit szabad vele |
|---|---|---|
| Nem mértük | a szenzor nem adott értéket | becsülhető, ha kimondod |
| Nem létezik | a parcellán nem volt vetés | NEM becsülhető |
| Hibás nulla | a kiesés nullaként rögzült | előbb meg kell találni |
A hiányzó értéket a legtöbben azonnal pótolni akarják. Előbb azt kell megkérdezni, mit jelent. Három különböző dolog néz ki ugyanúgy: nem mértük, nem létezik, vagy hibásan nullának rögzítették. A nem mért nedvességet érdemes lehet becsülni. A nem létezőt — mert a parcellán nem volt vetés — nem szabad. A hibás nullát pedig előbb meg kell találni, mert a becslést is elrontja. A háromból kettőt szokás összemosni, és ez csendes hiba.
Az ábra betöltése…
A demó saját ábrája, és a színek mondják meg a lényeget. Zöld, amit egy fél soros tartományellenőrzés megfog; piros, amit nem. Nézd meg, hogy a legnagyobb eltérések mind zöldek — a kilogramm per hektáros keveredés háromezer százaléka, a jelölt hiány mínusz háromszáztizennégye. És a két piros oszlop alig látszik: nulla egész hét és két egész kettő százalék. Ezek jutnak át egy jelentésbe.
A cella betöltése…
Itt a cella. A csavar a rossz egységű sorok aránya: emeld tíz százalékra. A kérdés az, hogy mikor bukik ki magától — vagyis hány százaléknál kezd el az összesítés láthatóan hazudni. Ha egy hiba elég ritka, semmilyen összesítés nem szól érte, és pontosan ezért kell soronkénti ellenőrzés.
Egy rossz időzóna a teljes napi és szezonális elemzést elcsúsztatja — és csendben teszi.
Egyetlen példa, mert ez a fajta hiba önálló dia értékű. A szenzor helyi időt küld, az adatbázis UTC-t tárol, a jelentés megint helyi időt mutat — és valahol a három között valaki nem konvertál. Az eredmény nem hibaüzenet, hanem egy-két órás eltolódás. A napi ciklus elcsúszik, az öntözési döntés rossz órára esik, és semmi nem jelez. Márciusban meg októberben pedig egy óra hirtelen megjelenik vagy eltűnik.
Az ábra betöltése…
A demó ábrája, mert a csúszás így válik láthatóvá. Két óránkénti átlaggörbe ugyanabból az adatból. A kék a helyes kezelés, a csúcsa tizennégy órakor. A piros ugyanaz, csak a helyi időt UTC-nek vettük — a csúcs tizenkettőre ment. Semmi más nem változott. És vedd észre: mindkét görbe teljesen hihetőnek néz ki. Ha csak az egyiket látnád, nem tűnne fel semmi.
A cella betöltése…
A cella itt fut. A csavar a csúcs órája: állítsd hatra, vagyis hajnalra. A kérdés az, hogy ugyanannyit csúszik-e. A válasz megmondja, hogy a hiba a csúcs HELYÉTŐL függ-e, vagy mindig ugyanakkora — és ez dönti el, hogy egy meglévő elemzést mennyire lehet utólag megjavítani.
A `w07-timezone` demó mérése: 8 760 órás megfigyelés, óránkénti átlag.
Az időzónahibát azért nehéz elhinni, mert nem ad hibaüzenetet. Itt látod, mit csinál. Egy évnyi órás talajhőmérséklet, a valódi napi csúcs délután kettőkor — ezt mi raktuk bele. A kék görbe a helyes kezelés: a csúcs tizennégy órakor. A piros ugyanaz az adat, csak a helyi időt UTC-nek vettük: a csúcs tizenkettőre csúszott. Két óra. Egy permetezési vagy öntözési ajánlásnál ez a különbség a hajnali és a déli beavatkozás között.
Nyers
Ez a hét utolsó szerkezeti gondolata. Három réteg. A nyers az adat úgy, ahogy érkezett — érintetlenül, akkor is, ha hibás. A javító lépés tisztít, típusoz, egységesít, és ez kód, nem kézi szerkesztés. Az elemzésre kész réteg az, amire az elemzés épül: típusos, dokumentált, és bármikor újraépíthető a nyersből. Ha a harmadik elromlik, nem katasztrófa — újra lefuttatod a lépést.
A kézi javítás egyszer működik. A kódba írt javítás minden új adagon lefut — és el lehet olvasni, mit tett.
A kézi javítás a legkényelmesebb és a legrosszabb megoldás. Megnyitod a táblázatot, kijavítod a három rossz értéket, elmented. Két hét múlva jön az új adat ugyanazzal a hibával, és senki nem tudja, mi történt először. A javítás akkor ér valamit, ha kód: le van írva, megismételhető, és a következő adagon magától lefut. Egy mondat különbség, de ez választja el a projektet a fenntartható munkától.
A `w07-timezone` demó mérése: a sorszám szerinti napvágás hatása egy teljes évre.
Egy konkrét eset arra, miért nem elég a kézi javítás. A sorszám szerinti napvágás a tavaszi óraátállítás után egy órát csúszik, és ez a csúszás az őszi átállásig megmarad. Nem egy nap romlott el, hanem kétszáztizennégy — az év ötvenkilenc százaléka. Egy kézi javítás ezt vagy végigkattintja kétszáztizennégyszer, vagy félbemarad. A kódba írt javítás egyszer íródik meg, minden új adagon lefut, és el lehet olvasni, mit tett. Ez a különbség nem kényelmi kérdés: a kézi javítás nem ellenőrizhető és nem ismételhető, tehát nem is része a módszernek.
Egy hozamtáblában néhány sor értéke háromezerszer nagyobb a többinél. Kollégád javasolja, hogy ezeket a sorokat töröljük, mert nyilván hibásak. Mi a helyesebb első lépés?
Egy hozamtáblában néhány sor értéke háromezerszer nagyobb a többinél. Kollégád javasolja, hogy ezeket a sorokat töröljük, mert nyilván hibásak. Mi a helyesebb első lépés?
Ugyanaz a lekérdezés háromszor. A beadandó egy táblázat és egy bekezdés: hol borul az első megoldás, és miért.
A heti küldetés ugyanaz a mérés, amit a blokkokban láttál, csak a te adatodon és a te gépeden. Egy több millió soros méréstábla, egy összegző lekérdezés, három út: memóriában betöltve, oszlopos fájlból, és beágyazott elemző motorral. A beadandó nem a nyertes megnevezése — az nem válasz. A beadandó az, hogy hol borul az első megoldás, és miért.
Az ábra betöltése…
A küldetés beadandója egy táblázat és egy bekezdés. Ez az ábra megmutatja, milyen az, amikor a bekezdés valamit állít. Bal oldalt a futásidő két kulcseloszlásra — és a ferde gyorsabb, ami az ellenkezője annak, amit én is vártam. Jobb oldalt ugyanaz szétosztott végrehajtásra: ott a ferde nyolcszoros helyett egy egész kettes gyorsulást ad. A beadandódban ilyen mondat kell: nem az, hogy melyik nyert, hanem hogy milyen feltétel mellett fordul meg az eredmény.
soronként egy mérés, vagy oszloponként egy jellemző; a kérdés alakja dönti el, melyik olcsóbb
szöveges csere, tömörített oszlopos tárolás, és a memóriabeli közös nyelv
az index a keresés gyorsítója, a terv pedig az, amit a motor TÉNYLEG csinál; a döntés a tervből jön, nem a másodpercből
sok apró írás kontra kevés, de nagy összegzés; két külön feladat, két külön motor
geometria pontokkal és poligonokkal, vagy szabályos rács cellákkal; a táblahatár az egyik, a műholdkép a másik
a beérkezett adat érintetlenül, és a belőle épített, javított változat; a kettő között a lépések kódban állnak
Ez volt a hetedik hét. Egy mondatban: a tárolás alakja a munkaterheléshez igazodik, és a legtöbb elemzési hiba nem a lekérdezésben keletkezik, hanem egy kimondatlan sémában.
| Rövidítés | Feloldás | Mit jelent |
|---|---|---|
| CSV | Comma-Separated Values | vesszővel elválasztott szöveges tábla: mindenhol megnyitható, de se sémája, se típusa nincs |
| SQL | Structured Query Language | a relációs lekérdezések nyelve; nem motor, hanem felület — több motor is érti |
| SCAN | a terv soronkénti végigolvasása | a lekérdezésterv szava: a motor az egész táblát elolvassa |
| SEARCH | a terv indexelt keresése | a lekérdezésterv szava: a motor odaugrik, nem olvas végig |
| OLTP | OnLine Transaction Processing | tranzakciós feldolgozás: sok apró írás és pontos sorlekérés |
| OLAP | OnLine Analytical Processing | elemző feldolgozás: kevés, de nagy összegző lekérdezés |
| UTC | Coordinated Universal Time | zónafüggetlen világidő; a tárolt időbélyeg alapja, a megjelenítés helyi idő |
| CAN | Controller Area Network | a járműves és gépi busz, amiről a telemetria jön |
| EOV | Egységes Országos Vetület | a magyar hivatalos síkvetület; a hazai földhivatali és üzemi adat ebben áll |
| WGS84 | World Geodetic System 1984 | a GPS és a műholdas adat globális rendszere — EOV-val összekeverve méteres hiba |
| GeoTIFF | georeferált TIFF | képfájl, amely a saját vetületét és helyét is tartalmazza |
| COG | Cloud-Optimised GeoTIFF | csempézett, több felbontású GeoTIFF: hálózaton is kiolvasható belőle egyetlen részlet |
| USING, COVERING | a lekérdezésterv szavai | `USING COVERING INDEX`: a motor magából az indexből válaszol, a táblához hozzá sem nyúl |
| NDVI | Normalized Difference Vegetation Index | normalizált vegetációs index; a térbeli fejezet tanpéldája |
| GIS | Geographic Information System | térinformatika; a PostGIS és a QGIS nevében is ez áll |
| PostgreSQL, MySQL, PostGIS | terméknevek, nem rövidítések | relációs motorok, illetve a PostgreSQL térbeli kiterjesztése |
Az adatbázisos hét rövidítései. A két vetületi kód külön figyelmet érdemel: agráradatot Magyarországon rendszeresen kapunk EOV-ban, a műholdas adatot viszont WGS84-ben — és a kettő összekeverése méteres hibát ad.
Az ábra betöltése…
Három típus, és ez nem szegényesség: a 7. hét majdnem minden mérése kategóriák összevetése — két formátum, két motor, két szétvágás —, oda pedig az oszlop való. A vonal ott jelenik meg, ahol az időrend maga az információ, a napi görbénél. A harmadik panel a demóábra: a hét néhány mérése olyan rajzot kíván, log tengelyt vagy hőtérképet, amit a dia saját rajzolója nem tud.
| diagramtípus | mit olvasol le róla | mire NEM jó |
|---|---|---|
| oszlop | kategóriák nagyságrendje és sorrendje — a hossz maga az érték | időbeli alakulás: a sorrend nem látszik rajta |
| vonal | időbeli alakulás: a meredekség és a fordulópontok | kategóriák összevetése: a vonal sorrendet állít oda is, ahol nincs |
| demóábra | amit a keretrendszer rajza nem tud: log tengely, hőtérkép, kis sokszorosok | saját adatod: ez a demó kimenete, nem szerkeszthető a dián |
A 7. hét szinte végig oszlopdiagramot használt, és ennek oka van: itt majdnem minden mérés kategóriák összevetése — két formátum, két motor, két szétvágás. Ahol idő van a vízszintes tengelyen, ott vonal áll, például a napi görbénél.