Aprofundează
Data warehouse
Un curs în 27 de lecții, fiecare cu o carte, un citat verificat și o lecție video de urmărit pe loc: de la Codd și Inmon la lakehouse și data mesh, modelare dimensională și SCD, ETL/ELT și calitate, pregătirea datelor pentru AI, pseudonimizare, k-anonimitate și confidențialitate diferențială, securitate, cloud sau on-prem, join-uri, indecși și memorie.
Traseul de lectură
- 01
Lecția 1 · Un depozit de date nu e o bază de date mai mare, ci una construită pentru altă întrebare.
Building the Data Warehouse · W. H. Inmon · 1992
Cele patru adjective ale lui Inmon sunt, de fapt, patru decizii de proiectare. Orientat pe subiect: datele sunt organizate pe client, produs, comandă — nu pe aplicațiile care le-au produs. Integrat: aceleași coduri de țară, aceleași unități, aceleași chei, oricâte surse ar fi în spate; integrarea e cea mai scumpă parte a muncii și motivul pentru care depozitul există. Variabil în timp: fiecare rând e o fotografie datată, iar istoricul se păstrează, nu se suprascrie. Nevolatil: se încarcă și se citește; nu se corectează pe loc, ca într-un sistem de tranzacții. Sistemul de producție răspunde la „care e adresa clientului acum?”. Depozitul răspunde la „cum s-a mutat valoarea comenzilor pe județe în ultimii cinci ani?”. Prima întrebare cere un rând, repede și consistent. A doua cere milioane de rânduri, comparabile între ele. Sunt două sarcini diferite, și lecțiile care urmează arată de ce nu le rezolvă bine același motor.
Un depozit de date este o colecție de date orientată pe subiect, integrată, variabilă în timp și nevolatilă, în sprijinul procesului decizional al conducerii.Building the Data Warehouse (1992), cap. 2 — definiția depozitului de date
De ce contează Fără un depozit, fiecare raport își face propria integrare — și fiecare o face puțin altfel. Deciziile cer istoric comparabil, iar istoricul comparabil e exact ce sistemele de producție nu păstrează.
Pe larg →Strânge ↑
Integrarea nu e o treabă făcută o dată. E o practică continuă. Fiecare sistem sursă vine cu obiceiurile lui: un magazin scrie „RO”, altul „România”, altul cod numeric. Depozitul alege o singură formă și o păstrează, pentru fiecare încărcare nouă. De aceea munca reală nu e copierea, ci traducerea — hotărârea ce înseamnă „același client” sau „aceeași vânzare” peste surse diferite. Gândește-te la două sucursale care țin evidența acelorași clienți cu nume scrise altfel. Fără o regulă comună, numărul clienților se dublează pe hârtie. Când traducerea devine disciplină zilnică, apare o întrebare nouă: ce facem cu rândurile vechi când regula se schimbă?
Pasajul anterior s-a oprit la întrebarea firească: ce facem cu rândurile vechi când regula de integrare se schimbă? Răspunsul lui Inmon e o decizie de proiectare, nu un accident: depozitul nu le șterge. El e nevolatil — datele se încarcă și se citesc, dar nu se corectează pe loc, ca într-un sistem de tranzacții. Dacă magazinul îți schimbă adresa, sistemul de producție suprascrie rândul vechi și gata. Depozitul păstrează ambele versiuni, fiecare datată. Apare astfel istoricul comparabil: poți vedea nu doar unde locuiește clientul acum, ci unde locuia când s-a făcut fiecare comandă. Gândește-te la un abonat care se mută din Cluj în București la mijlocul anului. Raportul pe județe are sens doar dacă comenzile din prima jumătate rămân legate de Cluj. Dar dacă nimic nu se șterge, depozitul crește neîncetat — și atunci apare o altă întrebare: cum găsești repede ce căutare într-o grămadă atât de mare?
Deschide pe YouTube ↗ - 02
Lecția 2 · Independența datelor: utilizatorul descrie ce vrea, nu unde stă.
A Relational Model of Data for Large Shared Data Banks · E. F. Codd · 1970
Codd a propus în 1970 ceva ce azi pare evident: tabele (relații) cu rânduri și coloane, chei primare care identifică un rând și chei străine care leagă tabelele, plus un limbaj declarativ în care spui ce rezultat vrei, nu ce fișiere să deschidă mașina. Normalizarea vine din aceeași idee: dacă o adresă de client apare în o mie de comenzi, o corectezi în o mie de locuri sau în niciunul. A treia formă normală se ține minte într-o frază: fiecare atribut depinde de cheie, de toată cheia și numai de cheie. Pentru un depozit de date, normalizarea e o alegere, nu o lege. Sursele sunt normalizate ca să scrie fără anomalii; depozitul denormalizează deliberat ca să citească fără zece join-uri. Ce rămâne neatins e principiul lui Codd: modelul logic separat de cel fizic. De aceea poți schimba indecși, partiții și formatul de stocare fără să rescrii interogările — și de aceea lecțiile despre indecși și memorie, de mai târziu, nu ating deloc SQL-ul.
Viitorii utilizatori ai marilor bănci de date trebuie protejați de obligația de a ști cum sunt organizate datele în mașină (reprezentarea internă).A Relational Model of Data for Large Shared Data Banks, Communications of the ACM 13(6), 1970 — prima propoziție a rezumatului
De ce contează Fiecare lecție de optimizare din acest curs se sprijină pe separarea logic–fizic. Cine o pierde ajunge să rescrie rapoartele de fiecare dată când mută un tabel.
Pe larg →Strânge ↑
Pasajul 1. Independența datelor are un preț ascuns: cineva trebuie să traducă cererea ta în pași fizici. Acel cineva e optimizatorul. Când scrii o interogare, nu alegi indecși sau ordinea join-urilor. Alegi motorul. E ca și cum ai spune taximetristului doar adresa, nu traseul. El cunoaște străzile, blocajele și scurtăturile. Dacă îi dictăm traseul, pierdem exact ce ne-a dat Codd: libertatea de a schimba harta fără să schimbăm destinația. Dar ce se întâmplă când optimizatorul greșește traseul? Acolo începe lecția următoare.
Aceeași separare are o a doua față: datele înseși trebuie ținute într-un singur loc. Dacă adresa unui client e copiată în o mie de comenzi, o mutare înseamnă o mie de corecturi — și o mie de șanse să uiți una. Normalizarea spune: scrie adresa o singură dată, într-un rând propriu, și leagă restul printr-o cheie. E ca numărul de matricolă dintr-o facultate: nu rescrii numele studentului în fiecare registru, doar codul. Regula de aur a celei de-a treia forme normale se reduce la o frază: fiecare valoare depinde de cheie, de toată cheia și numai de cheie. Dar dacă vrei să citești rapid, nu să scrii curat? Acolo normalizarea devine o alegere, nu o lege.
Deschide pe YouTube ↗ - 03
Lecția 3 · Un motor bun la tranzacții e slab la analiză, și invers — nu e un defect, e fizică.
“One Size Fits All”: An Idea Whose Time Has Come and Gone · Michael Stonebraker, Uğur Çetintemel · 2005
OLTP (procesare de tranzacții): mii de operații mici pe secundă, fiecare atinge câteva rânduri întregi — o comandă, un client — și trebuie să fie corectă chiar dacă alte mii se întâmplă simultan. De aici stocarea pe rânduri, indecșii B-tree și izolarea tranzacțiilor. OLAP (procesare analitică): câteva interogări mari, fiecare atinge două-trei coloane din sute de milioane de rânduri și le adună. De aici stocarea pe coloane, compresia și scanarea în loturi. Stonebraker a spus-o în 2005: era unui singur motor pentru toate s-a încheiat, iar de atunci au apărut motoare columnare, de streaming, de serii de timp, de documente. Sistemele HTAP încearcă ambele într-unul; prețul e complexitatea și, de obicei, o copie columnară ținută la zi în fundal. Regula practică: nu rula rapoarte pe baza de producție. O scanare analitică pe un motor de tranzacții blochează sau încetinește scrierile și folosește greșit indecșii. Replica de citire e primul ajutor; depozitul e tratamentul.
Ultimii 25 de ani de dezvoltare comercială a SGBD-urilor pot fi rezumați într-o singură formulă: «o mărime pentru toți». Formula se referă la faptul că arhitectura tradițională de SGBD (proiectată și optimizată inițial pentru prelucrarea datelor de afaceri) a fost folosită pentru a susține multe aplicații centrate pe date, cu caracteristici și cerințe foarte diferite.“One Size Fits All”: An Idea Whose Time Has Come and Gone, ICDE 2005 — rezumat
De ce contează Cea mai frecventă cauză a unui sistem de producție lent nu e volumul de tranzacții, ci raportul de dimineață care scanează tot tabelul de comenzi.
Pe larg →Strânge ↑
De ce nu poți optimiza pentru ambele deodată? Pentru că cerințele se bat la nivel de fizică. Un motor de tranzacții citește rânduri întregi, ca un chelner care aduce farfuria completă: comandă, client, adresă, tot. Exact ce vrei când procesezi o plată. Un raport analitic vrea doar coloana cu totalurile, din milioane de rânduri. Aducea farfurii complete ar fi ca să cumperi un întreg raft de supermarket ca să iei o pâine. Pe coloane, citești doar ce te interesează și comprimi eficient, pentru că valorile asemanătoare stau lipite. Pe rânduri, compresia asta e aproape imposibilă. Alegerea nu e despre gust, ci despre cum circulă datele prin memorie și disc. Dar dacă totuși ai nevoie de ambele în același sistem? Aici apare compromisul HTAP.
Deschide pe YouTube ↗ - 04
Lecția 4 · Declară granularitatea înainte de orice; restul modelului decurge din ea.
The Data Warehouse Toolkit · Ralph Kimball, Margy Ross · 2013
Cei patru pași ai lui Kimball sunt în ordinea asta dintr-un motiv. Procesul de afaceri e un lucru care se întâmplă — o vânzare, o plată, un transport — nu un departament. Granularitatea e propoziția care spune ce reprezintă un rând din tabelul de fapte: „o linie de bon, într-un magazin, într-o zi”. Abia apoi vin dimensiunile — cine, ce, unde, când, contextul descriptiv — și faptele, măsurile numerice care se pot aduna la granularitatea aleasă. Rezultatul e schema stea: un tabel de fapte îngust și lung, cu chei străine spre dimensiuni late și denormalizate, fiecare cu o cheie surogat (un întreg generat de depozit, nu codul din sursă). Greșeala clasică e să amesteci granularități — linii de comandă și totaluri de comandă în același tabel — și să obții sume duble în primul raport. A doua greșeală e să ai trei dimensiuni „Client” ușor diferite; dimensiunile conformate, aceleași pentru toate procesele, sunt ce face două rapoarte comparabile.
Alege procesul de afaceri. Declară granularitatea. Identifică dimensiunile. Identifică faptele.Kimball Group, Dimensional Modeling Techniques — Four-Step Dimensional Design Process (aceiași pași ca în The Data Warehouse Toolkit, ed. a 3-a, cap. 3)
De ce contează Un tabel de fapte cu granularitate nedeclarată produce cifre care se contrazic între rapoarte, iar nimeni nu poate spune care e cea corectă.
Pe larg →Strânge ↑
Propoziția de granularitate e mai mult decât o declarație: e un test. Odată ce spui „un rând înseamnă o linie de bon”, poți verifica orice coloană împotriva ei. O măsură care nu se adună corect la nivelul acela — de pildă prețul total al bonului, repetat pe fiecare linie — nu are ce căuta acolo. Exemplul de zi cu zi: bonul de la magazin are linii, dar și un total jos. Dacă torni ambele în același tabel și aduni, totalul bonului plătește de trei ori. Granularitatea declarată te oprește înainte să scrii prima interogare. Devine și un contract între echipă și utilizatori: toți știu ce reprezintă un rând, deci o sumă înseamnă același lucru pentru toți. Următorul pas e să vezi ce se întâmplă când realitatea nu se încadrează într-o singură granularitate.
Deschide pe YouTube ↗ - 05
Lecția 5 · Data Vault separă ce e stabil (cheile), ce leagă (relațiile) și ce se schimbă (atributele).
Data Vault Series 1 — Data Vault Overview · Dan Linstedt · 2002
Schema stea e rapidă de citit și ușor de înțeles, dar rigidă: o sursă nouă sau o coloană nouă înseamnă rescrierea dimensiunii. Fulgul de zăpadă normalizează dimensiunile — mai puține duplicate, mai multe join-uri — și de obicei nu merită. Data Vault răspunde la altă problemă: cum integrezi douăzeci de surse care se schimbă des, fără să rescrii nimic și cu audit complet. Trei tipuri de tabele: hub (cheile de business — un client, un produs), link (relațiile dintre chei — clientul a cumpărat produsul) și satellite (atributele descriptive, cu data încărcării și sursa, deci cu istoric complet). Costul e că un vault nu se citește direct: are prea multe tabele. Arhitectura tipică e staging, apoi vault (brut și de business), apoi marts în stea deasupra, pentru rapoarte. Alegerea nu e ideologică. Surse puține și stabile: stea direct. Surse multe, schimbătoare, cerințe de audit: vault dedesubt, stea deasupra.
Modelul Data Vault este un set de tabele normalizate, orientat pe detaliu, cu urmărire istorică și legături unice, care susține una sau mai multe arii funcționale ale afacerii.Dan Linstedt, Data Vault Series 1 — Data Vault Overview (2002), definiția modelului
De ce contează Un depozit care se rescrie la fiecare sursă nouă nu ajunge niciodată la a zecea sursă. Alegerea modelului decide cât de ieftină e schimbarea.
Pe larg →Strânge ↑
Pasajul de față privește ce se întâmplă când sursele nu doar se schimbă, ci se contrazic. Două sisteme pot da același client cu nume scrise diferit. În Data Vault, hub-ul păstrează o singură cheie pentru client, iar sateliții păstrează ambele versiuni, fiecare cu sursa ei. Nimeni nu șterge nimic ca să rezolve conflictul. Adevărul devine o alegere făcută târziu, la raport, nu devreme, la încărcare. Gândește-te la două facturi de la aceeași adresă, cu nume scrise altfel: le păstrezi pe ambele și decizi mai târziu care e cea corectă. Asta mută decizia acolo unde are context. Dar cum se leagă practic cheile între surse, când niciuna nu e sursa adevărului? Asta deschide pasul următor.
Pasajul de față răspunde la întrebarea de dinainte: cine leagă cheile când niciun sistem nu e sursa adevărului. Răspunsul e că nimeni nu e proprietar. Hub-ul e o ancoră neutră: el recunoaște un client indiferent de sistemul care l-a trimis. Link-ul înregistrează relația de fiecare dată când o sursă o afirmă, cu sursa ei. Deci legătura nu e o opinie a unui sistem, ci o colecție de afirmații. E ca o agendă de contacte în care scrii că Ana cunoaște pe Ion pentru că trei prieteni ți-au spus asta, fiecare cu numele lui lângă. Nicio sursă nu dictează, dar toate lasă urmă. Asta face cheile stabile chiar dacă sistemele se schimbă. Dar dacă cheile sunt stabile, atributele din jur nu sunt. Cum se schimbă ele fără să piardă istoria? Asta e pasul următor.
Deschide pe YouTube ↗ - 06
Lecția 6 · Lakehouse: fișiere deschise pe stocare de obiecte, cu tranzacții și schemă deasupra.
Lakehouse: A New Generation of Open Platforms that Unify Data Warehousing and Advanced Analytics · Michael Armbrust, Ali Ghodsi, Reynold Xin, Matei Zaharia · 2021
Data lake-ul a promis stocare ieftină pentru orice: fișiere Parquet pe stocare de obiecte, fără schemă impusă, fără tranzacții. A livrat, adesea, o mlaștină: nimeni nu știe ce e curat, două joburi scriu peste același director, o citire prinde jumătate dintr-o scriere. Depozitul clasic are tranzacții, schemă și viteză, dar într-un format închis, ca o copie a datelor. Lakehouse-ul pune între ele un format de tabel deschis (Delta, Iceberg, Hudi): un jurnal de metadate peste fișierele Parquet care aduce tranzacții ACID, „time travel” la o versiune anterioară, evoluție de schemă și, mai ales, mai multe motoare — SQL, Spark, un framework de ML — care citesc aceleași fișiere fără copii. Arhitectura medalion organizează straturile: bronze (datele exact cum au sosit, niciodată modificate), silver (curățate, deduplicate, cu tipuri corecte), gold (agregate, modelate pentru consum — de obicei în stea). Regula de aur e că bronze e dovada: orice din silver și gold trebuie să se poată reconstrui din el.
Această lucrare susține că arhitectura depozitului de date, așa cum o știm astăzi, se va ofili în anii următori și va fi înlocuită de un nou tipar arhitectural, Lakehouse, care (i) se va baza pe formate deschise, cu acces direct, precum Apache Parquet, (ii) va avea suport de prim rang pentru învățare automată și știința datelor și (iii) va oferi performanță de ultimă generație.Lakehouse: A New Generation of Open Platforms that Unify Data Warehousing and Advanced Analytics, CIDR 2021 — rezumat
De ce contează Când o transformare se dovedește greșită peste șase luni, singura întrebare care contează e dacă mai ai datele brute. Bronze răspunde da.
Pe larg →Strânge ↑
Cardul spune ce aduce jurnalul de metadate. Hai să vedem ce schimbă el de fapt în muncă. Când două joburi scriau în același director, rezolvarea era coordonare umană: cine scrie, când, cu ce acord. Jurnalul mută această înțelegere în sistem. Scrierea fie ajunge completă, fie deloc, iar cititorii văd mereu o versiune coerentă. Nu mai e nevoie de cineva care să păzească folderul. Un exemplu obișnuit: ca la un document partajat cu istoric de versiuni, unde poți reveni la varianta de ieri fără să salvezi copii manual. Asta deschide o întrebare nouă: dacă fiecare scriere e înregistrată, cine are voie să scrie, și cum decizi asta?
Pasajul anterior s-a oprit la o întrebare: cine are voie să scrie? Răspunsul lakehouse-ului e simplu: jurnalul devine punctul de control. Fiecare scriere e o operație înregistrată, deci poate fi verificată înainte să ajungă în tabel. Sistemul poate refuza un fișier cu tipuri greșite sau o coloană lipsă, exact ca un portar care nu lasă în sală decât pe cei cu bilet. În data lake-ul vechi, datele stricate intrau oricum; curățarea se făcea abia după, cu durere. Aici, poarta e la intrare. Exemplu de zi cu zi: un formular online care nu acceptă un email fără simbolul @, în loc să lase greșeala să ajungă în baza de date și să o cauți apoi. Dar o poartă strictă nu garantează că datele sunt corecte, doar că arată așa. Cum arătăm, atunci, că datele au fost curățate cu grijă?
Deschide pe YouTube ↗ - 07
Lecția 7 · Data mesh mută proprietatea datelor la domeniul care le produce; platforma și regulile rămân comune.
Data Mesh Principles and Logical Architecture · Zhamak Dehghani · 2020
Problema pe care o rezolvă data mesh-ul e organizațională: echipa centrală de date devine gât de sticlă și nu cunoaște semantica a douăzeci de domenii; când comanda „a fost anulată” înseamnă altceva în logistică decât în facturare, echipa centrală află ultima. Primul principiu mută proprietatea la domeniu. Al doilea cere ca ce publică domeniul să fie un produs: set de date cu schemă, proprietar, SLA, documentație, adresă de acces — descoperibil, de încredere, interoperabil. Al treilea, platforma self-serve, e ce face primele două posibile: echipele publică fără să-și construiască fiecare propria infrastructură. Al patrulea, guvernanța federată computațională, spune că regulile comune — ce e PII, ce formate, ce identificatori — sunt cod verificat automat, nu un comitet. Capcana: mesh fără platformă înseamnă douăsprezece depozite incompatibile cu un nume nou. Și scara contează: pentru o firmă cu o singură echipă de date, un depozit central bine modelat e răspunsul corect, nu o versiune diminuată de mesh.
Proprietate și arhitectură descentralizate ale datelor, orientate pe domenii. Datele ca produs. Infrastructura de date self-serve ca platformă. Guvernanță computațională federată.Data Mesh Principles and Logical Architecture, martinfowler.com (2020) — cele patru principii, în ordinea din articol
De ce contează Cele mai multe eșecuri de „mesh” sunt eșecuri de platformă: s-a descentralizat proprietatea înainte să existe ceva comun pe care să se publice.
Pe larg →Strânge ↑
Cardul spune cine devine proprietar. Pasul următor e de ce: proprietatea nu e doar o sarcină, ci o cunoaștere. Cine produce datele înțelege ce înseamnă ele cu adevărat. Când comanda „a fost anulată” înseamnă altceva în logistică decât în facturare, nimeni dintr-o echipă centrală nu poate ghici asta corect. E ca și cum ai cere unei traduceri să traducă un contract juridic fără să fi văzut vreodată unul. Mutarea proprietății la domeniu mută decizia semantică acolo unde trăiește sensul. Echipa centrală nu dispare; încetează doar să mai fie gâtul prin care trec toate întrebările despre semnificație. Dar odată ce fiecare domeniu deține sensul propriu, apare o întrebare nouă: ce anume publică el, ca ceilalți să poată avea încredere?
Pasajul 1 s-a oprit la întrebarea încrederii. Răspunsul lui Dehghani e că domeniul nu publică un set de date, ci un produs. Un produs are un utilizator, o promisiune și un responsabil. O schemă, documentație, o adresă de acces și o înțelegere despre cât de proaspete sunt datele. Gândește-te la un apartament închiriat: nu-ți dă cheia și atât, ci un contract, un proprietar de contactat, o descriere exactă. Fără acestea, fiecare echipă consumatoare trebuie să sune la cineva și să întrebe ce înseamnă fiecare coloană. Asta reface gâtul de sticlă pe altă ușă. Tratând datele ca produs, echipa de logistică nu mai răspunde la telefoane; răspunde cu un catalog clar. Dar un produs bun are nevoie de un raft pe care să-l așezi. De unde vine acel raft comun?
Deschide pe YouTube ↗ - 08
Lecția 8 · Stocarea pe coloane, compresia și execuția vectorizată sunt de ce o interogare pe un miliard de rânduri durează secunde.
C-Store: A Column-oriented DBMS · Michael Stonebraker et al. · 2005
Trei idei explică aproape tot din bazele de date analitice moderne. Prima: stocarea pe coloane. O interogare care atinge trei coloane din cincizeci citește 6% din octeți, nu 100%. A doua: compresia. Într-o coloană, vecinii seamănă — aceeași țară de o mie de ori, date crescătoare, sume din același interval — deci dicționar, run-length și delta comprimă de zece ori, iar motorul poate lucra adesea direct pe datele comprimate. A treia: execuția vectorizată, în loturi de mii de valori, nu tuplu cu tuplu, ca procesorul să nu aștepte memoria. Peste ele stau două decizii de arhitectură. MPP (procesare masiv paralelă): datele sunt partiționate pe noduri, fiecare scanează partea lui, iar join-urile și agregările cer redistribuire (shuffle) — partea scumpă. Separarea stocare–calcul: datele stau pe stocare de obiecte, ieftină și durabilă, iar calculul se pornește la cerere și se scalează separat; prețul e latența la rece și cache-ul local. Micro-partițiile poartă min/max per bloc, deci un filtru pe dată sare peste blocurile care nu-l pot conține. Ce nu merge bine pe columnar: scrieri mici și dese — se încarcă în loturi.
Această lucrare prezintă proiectarea unui SGBD relațional optimizat pentru citire, care contrastează puternic cu majoritatea sistemelor actuale, optimizate pentru scriere.C-Store: A Column-oriented DBMS, VLDB 2005 — prima propoziție a rezumatului
De ce contează Cine înțelege de ce columnarul e rapid scrie interogări care filtrează pe coloanele partiționate și evită să insereze rând cu rând într-un motor analitic.
Pe larg →Strânge ↑
Cardul explică de ce columnarul citește puțin. Pasul următor: aceleași trei idei schimbă modul în care gândești interogarea, nu doar motorul. Ordinea coloanelor în filtru contează mai puțin decât care coloane apar deloc. O interogare care cere patru coloane când îi trebuie două plătește de patru ori la citire, chiar și comprimat. Iar compresia nu e doar spațiu: un dicționar transformă comparații pe șiruri lungi în comparații pe numere mici, deci filtrele devin mai rapide, nu doar mai mici. Exemplu: dacă raportul tău folosește doar lună și țară, nu scrie SELECT cu stea din reflex — numește exact coloanele. Următorul pas: ce se întâmplă când datele tocmai au sosit și nu pot aștepta un lot.
Deschide pe YouTube ↗ - 09
Lecția 9 · Log-ul e sursa adevărului; baza de date e un cache al ultimei valori din log.
The Log: What every software engineer should know about real-time data's unifying abstraction · Jay Kreps · 2013
Un log e o listă la care doar adaugi, în ordine. Pare banal, dar e abstracția care leagă replicarea, streaming-ul și depozitul de date. Orice bază relațională are unul înăuntru — jurnalul de tranzacții — și fiecare insert, update sau delete trece pe acolo înainte să ajungă în tabele. Change data capture (CDC) citește exact acel jurnal și emite fiecare schimbare ca eveniment: fără interogări periodice care încarcă sursa, fără fereastra pierdută dintre două rulări și, mai ales, cu ștergerile incluse — un SELECT de noapte nu vede niciodată rândul care a dispărut la prânz. Evenimentele ajung într-un log distribuit; consumatorii le citesc cu un offset, deci pot reporni de unde au rămas sau, dacă e nevoie, de la zero. În depozit, bronze primește evenimentele brute, iar silver aplică „ultima valoare per cheie” (merge) sau păstrează tot istoricul. Semantica realistă e cel-puțin-o-dată plus idempotență: fiecare eveniment poartă cheie și versiune, iar aplicarea lui de două ori dă același rezultat. Ordinea contează per cheie, nu între chei.
Un log este poate cea mai simplă abstracție de stocare posibilă. Este o secvență de înregistrări doar-cu-adăugare, total ordonată, ordonată în timp.The Log: What every software engineer should know about real-time data's unifying abstraction, LinkedIn Engineering (2013) — Part One: What Is a Log?
De ce contează Extragerea periodică cu SELECT ratează ștergerile și încarcă sursa; un depozit alimentat așa își pierde încet acuratețea fără să dea nicio eroare.
Pe larg →Strânge ↑
Dacă log-ul e sursa adevărului, apare o consecință neobișnuită: tabelele nu mai sunt sacre. Ele devin o viziune materializată — un rezultat calculat din evenimente, care poate fi refăcut de la zero oricând. Asta schimbă felul în care gândești greșelile. O migrare ratată sau o logică greșită nu mai e o catastrofă, ci o repornire: arunci tabela, corectezi transformarea, rejucai log-ul. La fel cum poți rescrie o rețetă și găti din nou din aceleași ingrediente, fără să fi pierdut nimic. Baza de date nu mai e depozitul adevarului, ci un cache al ultimei valori, reconstruibila din jurnal. Dar dacă log-ul poate reface orice, apare întrebarea firească: cât timp trebuie păstrat acel log?
Pasajul anterior s-a încheiat cu o întrebare: cât trebuie păstrat log-ul? Răspunsul surprinde: nu pentru totdeauna. Pentru că tabela poate fi reconstruită din orice punct, e suficient un instantaneu plus evenimentele de după el. Multe sisteme merg mai departe și păstrează în log doar ultima valoare per cheie, printr-un proces numit compactare. E ca agenda din telefon: nu ții fiecare versiune veche a fiecărui număr, doar starea actuală, și totuși poți suna pe oricine. Istoricul complet devine o alegere, nu o obligație — îl păstrezi doar dacă vrei să răspunzi la întrebări despre trecut. Dar dacă log-ul e atât de central, apare o problemă practică: ce se întâmplă când mai multe servicii vor să scrie în el în același timp?
Deschide pe YouTube ↗ - 10
Lecția 10 · Contabilii nu folosesc radiera: înregistrezi fapte, derivezi stări și recalculezi când ai greșit.
Immutability Changes Everything · Pat Helland · 2015
Un contabil nu șterge o înregistrare greșită; adaugă una de corecție. Registrul rămâne complet, oricine poate reface calculul, iar „soldul” e o valoare derivată, nu un fapt. Helland arată că tot calculul modern merge în direcția asta: jurnale de tranzacții, log-uri de evenimente, fișiere Parquet scrise o dată, chiar și SSD-urile care nu suprascriu pe loc. Când datele sunt imuabile, dispar clasele întregi de probleme — actualizări pierdute, citiri inconsistente, „cine a schimbat asta?” — și apar două lucruri prețioase: auditul e gratis și orice stare se poate recalcula. Într-un depozit de date, faptele sunt natural imuabile: o vânzare s-a întâmplat. Corecțiile devin rânduri noi cu semn invers sau cu perioadă de valabilitate, iar faptele care sosesc târziu se adaugă, nu se „lipesc” în trecut. Dimensiunile își păstrează istoricul prin versiuni — lecția următoare. Singurul conflict real e cu dreptul la ștergere din GDPR, pentru care există un răspuns compatibil cu imuabilitatea, în lecția 19.
Există o tendință de neoprit spre stocarea și transmiterea de date imuabile. Avem nevoie de imuabilitate ca să ne coordonăm la distanță și ne putem permite imuabilitatea, pe măsură ce stocarea se ieftinește.Immutability Changes Everything, CIDR 2015 — rezumat (secțiunea 2 se numește „Accountants Don't Use Erasers”)
De ce contează Un depozit care se corectează pe loc nu poate răspunde la „ce arăta raportul luna trecută și de ce”. Unul doar-cu-adăugare răspunde întotdeauna.
Pe larg →Strânge ↑
Pasajul 1: Gândește-te la extrasul de cont. Banca nu-ți trimite un sold pe care să-l ai de crezut; îți trimite lista de mișcări, iar soldul e doar suma lor. Poți contesta o linie, nu o concluzie. Aici e răsucirea pe care Helland o propune: oprește-te din a întreba „ce valoare e corectă acum?” și întreabă „ce evenimente s-au întâmplat?”. Valoarea devine un rezultat, nu o decizie. Asta schimbă și felul în care construiești software-ul: nu mai scrii cod care împrăștie actualizări în zece tabele, ci cod care reacționează la evenimente și recalculează. Greșelile nu mai sunt catastrofe de reparat în secret, ci evenimente noi, vizibile. Iar când totul e vizibil, apare o întrebare mai grea: ce faci cu faptele care nu se pot schimba niciodată, dar pe care legea spune că trebuie să le poți șterge?
Deschide pe YouTube ↗ - 11
Lecția 11 · SCD tip 2: când un atribut se schimbă, nu suprascrii — adaugi un rând și închizi perioada celui vechi.
The Data Warehouse Toolkit · Ralph Kimball, Margy Ross · 2013
Un client se mută din Cluj în Iași. Ce faci cu rândul lui din dimensiunea Client? Tip 1: suprascrii. Simplu, fără istoric — iar vânzările din 2023 apar brusc în Iași, deci rapoartele vechi se schimbă. Bun pentru corectarea greșelilor și pentru atribute fără valoare istorică. Tip 2: adaugi un rând nou, cu o cheie surogat nouă, cu valid_from și valid_to, și marchezi care e curent. Faptele vechi rămân legate de versiunea de atunci, faptele noi de versiunea nouă; raportul din 2023 rămâne exact cum era. Tip 3: păstrezi o coloană „valoarea anterioară” — un singur pas de istoric, util la realinieri de teritorii de vânzări, unde vrei să vezi ambele împărțiri deodată. Alegerea se face per atribut, nu per tabel: aceeași dimensiune poate avea coloane tip 1 și tip 2. Două capcane. Prima: join-ul faptelor pe cheia naturală în loc de surogat, care dublează rândurile de câte versiuni are clientul. A doua: un „update” de tip 1 rulat din greșeală pe o dimensiune tip 2, care rescrie toate versiunile deodată și șterge istoricul fără să dea nicio eroare.
Schimbările de tip 2 într-o dimensiune cu schimbare lentă adaugă un rând nou în dimensiune, cu valorile actualizate ale atributelor. Asta cere generalizarea cheii primare a dimensiunii dincolo de cheia naturală sau durabilă, pentru că vor exista, potențial, mai multe rânduri care descriu fiecare membru.Kimball Group, Dimensional Modeling Techniques — Type 2: Add New Row (The Data Warehouse Toolkit, ed. a 3-a, cap. 5)
De ce contează Fără tip 2, „vânzări pe județ în 2023” dă alt răspuns în fiecare an, pe măsură ce clienții se mută. Istoricul trebuie ținut în dimensiune, nu ghicit din fapte.
Pe larg →Strânge ↑
Pasajul 1. Odată ce ai istoric în dimensiune, apar două moduri diferite de a pune o întrebare. Poți întreba „ce știam atunci”: raportul din 2023 folosește versiunile de client valabile în 2023, deci mutările ulterioare nu contează. Sau poți întreba „cum arată totul acum”: aici ignori perioadele și iei doar rândul marcat ca curent pentru fiecare client. Ambele sunt legitime, dar cer interogări diferite, iar confuzia dintre ele e o sursă frecventă de neînțelegeri între analiști. Exemplu: un magazin vrea să știe unde livra în 2023 (răspunsul „atunci”), dar și câți clienți au azi adresă în Iași (răspunsul „acum”). Aceeași tabelă, două lecturi. Următorul pas: ce se întâmplă cu dimensiunea când clienții se mută des și istoricul crește necontrolat.
Deschide pe YouTube ↗ - 12
Lecția 12 · Datele supraviețuiesc codului: orice schimbare de schemă trebuie citită și de codul vechi, și de cel nou.
Designing Data-Intensive Applications · Martin Kleppmann · 2017
O aplicație se înlocuiește în cinci minute; datele ei stau cinci ani. De aici două compatibilități: înapoi (codul nou citește datele vechi) și înainte (codul vechi citește datele noi — fiindcă niciodată nu se actualizează totul deodată). Regulile care le păstrează pe amândouă sunt puține și stricte: adaugi coloane opționale, nu refolosești niciodată un nume cu alt sens, nu schimbi tipul pe loc. O schimbare de tip se face în patru pași: adaugi coloana nouă, o umpli (backfill), muți cititorii, abia apoi ștergi vechea. Formatele cu schemă (Avro, Protobuf, Parquet) fac regulile verificabile; JSON-ul liber le lasă pe seama norocului. Contractul de date e aceeași idee, ridicată la nivel de echipă: producătorul și depozitul cad de acord pe schemă, semantică, SLA, proprietar și politica de schimbare, iar acordul e verificat automat la fiecare publicare. O schimbare care rupe contractul se publică ca versiune nouă, alături de cea veche. Motivul e că cele mai grave defecte sunt tăcute: o coloană redenumită la sursă sosește ca NULL, raportul scade cu 30% și nimeni nu primește nicio eroare. Contractul o prinde la graniță, unde e ieftin.
Astfel, datele vechi de cinci ani vor fi tot acolo, în codificarea originală, dacă nu le-ai rescris explicit între timp. Observația aceasta e rezumată uneori prin: datele supraviețuiesc codului.Designing Data-Intensive Applications (2017), cap. 4 Encoding and Evolution — Dataflow Through Databases
De ce contează O schimbare de schemă neanunțată nu dă eroare; dă un raport greșit, descoperit peste o lună. Contractul mută descoperirea la graniță și la minut.
Pe larg →Strânge ↑
Pasajul 1. Schema nu e ceva pe care îl stabilești o dată, ci ceva ce practici la fiecare publicare. Kleppmann arată că datele vechi rămân codificate așa cum au fost scrise, deci un depozit de cinci ani conține de fapt toate versiunile prin care a trecut schema. Citești simultan înregistrări din trei epoci. De aceea migrația nu e un proiect, ci o rutină: la fel ca spălatul pe dinți. Exemplu concret: într-un magazin online, comanda de anul trecut are câmpul TVA ca număr, cea de azi ca text; raportul anual trebuie să le înțeleagă pe amândouă. Întrebarea care se deschide: cine decide când o versiune a schemei a murit de tot?
Pasajul 2. Răspunsul la întrebarea dinainte e simplu: versiunea moare când ultimul cititor al ei dispare, nu când apare cea nouă. De aceea Kleppmann insistă pe compatibilitate înainte: codul vechi trebuie să citească datele noi, fiindcă actualizarea nu se face niciodată deodată. Într-o aplicație mobilă, unii utilizatori nu mai fac actualizarea luni de zile; serverul care scrie formatul nou trebuie să le rămână lizibil și lor. Regula practică e să adaugi doar câmpuri opționale și să nu refolosești niciodată un nume cu alt sens. O schimbare de tip nu se face pe loc, ci în patru pași: coloană nouă, umplere, mutarea cititorilor, abia apoi ștergerea. Formatele cu schemă fac aceste reguli verificabile automat; JSON-ul liber le lasă la noroc. Dar verificarea automată are nevoie de cineva care să definească ce înseamnă valid — și asta duce la contractul de date.
Contractul de date duce schema din cod în relația dintre echipe. Producătorul și depozitul cad de acord pe schemă, sens, proprietar și reguli de schimbare, iar acordul e verificat automat la fiecare publicare. De ce merită asta: cele mai grave defecte nu fac zgomot. Dacă cineva redenumește la sursă o coloană, ea sosește ca NULL, raportul scade luni și nimeni nu vede nicio eroare. Contractul mută descoperirea la graniță, unde e ieftin, nu în raportul directorului, unde e scump. O schimbare care ar rupe contractul se publică ca versiune nouă, alături de cea veche, ca un pod care nu se închide până nu se deschide altul. Exemplu: un contabil primește lunar fișierul de cheltuieli; dacă banca schimbă tăcut formatul, contractul oprește fișierul în aceeași zi. Rămâne o întrebare: cine plătește când contractul e încălcat?
Pasajul 4. Răspunsul la întrebarea dinainte: plata o suportă producătorul, nu depozitul. Contractul nu e doar o verificare tehnică, ci o alocare de responsabilitate. Dacă schimbarea ta rupe acordul, incidentul e al tău, cu remedierea și comunicarea. De ce contează asta: fără contract, costul greșelii se mută tăcut în aval, la echipa care are cel mai puțină putere să-l prevină. Cu contract, stimulentul ajunge acolo unde se ia decizia de schimbare. Exemplu: dacă echipa de livrări schimbă tăcut codul de la "kg" la "bucăți", ea plătește corecția facturilor, nu depozitul care le-a citit orbește. Nu e despre vină, ci despre cine poate fixa problema cel mai repede. Asta ridică următoarea întrebare: ce se întâmplă când contractul e respectat, dar sensul câmpului se schimbă subtil, fără să spargă nimic?
Pasajul 5. Când contractul e respectat dar sensul alunecă, verificarea automată nu te mai ajută, pentru că mașina vede doar tipuri, nu intenții. Kleppmann distinge exact asta: schema poate garanta că un câmp e număr, nu și ce înseamnă numărul. O coloană "status" poate primi o valoare nouă, validă ca text, dar pe care niciun raport nu o înțelege. De aceea contractul are o parte pe care nicio unealtă nu o poate verifica: semantica, scrisă în cuvinte, cu exemple și cu lista valorilor permise. Exemplu concret: o farmacie trimite "cantitate" mereu ca număr întreg valid, dar începe să înregistreze doze în loc de cutii; toate verificările trec, stocul devine fals. Aici singura apărare e o persoană care citește acordul, nu un script. Asta deschide întrebarea următoare: cum arată în practică o schimbare de sens făcută corect, cu anunț și cu perioadă de dublă citire?
Răspunsul la întrebarea dinainte: sensul îl ține minte contractul, nu codul. Codul execută; el nu explică. De aceea acordul dintre echipe include un dicționar de date, cu un proprietar pe câmp, care răspunde la întrebarea ce înseamnă. Când proprietarul pleacă din firmă, cunoașterea nu pleacă cu el, fiindcă e scrisă la graniță, nu în capul cuiva. Exemplu: după doi ani, nimeni nu mai știe de ce există coloana "cod_vechi"; o privire în dicționar spune cine a pus-o, când și de ce. Astfel schema devine o memorie a organizației, nu doar o formă de verificat. Rămâne deschis: ce se întâmplă când datele istorice, scrise cu sensul de ieri, trebuie citite cu regulile de azi?
Deschide pe YouTube ↗ - 13
Lecția 13 · ELT mută transformarea în depozit; ce rămâne de proiectat sunt orchestrarea și idempotența.
Fundamentals of Data Engineering · Joe Reis, Matt Housley · 2022
ETL transformă datele într-o unealtă separată înainte să le încarce; ELT le încarcă brute și le transformă cu SQL în depozit, unde calculul e ieftin, SQL-ul stă în git și proveniența se citește din interogări. Ordinea nouă face extragerea subțire (copiază fidel) și transformarea bogată (modelează, testează, documentează). Orchestrarea e graful de sarcini: dependențe, program, reîncercări, alerte, o vedere a ce a rulat și ce nu. Parametrul unei rulări e fereastra de timp, niciodată „acum” — altfel rularea de ieri nu se mai poate repeta. Idempotența e proprietatea care face totul reparabil: rularea repetată pentru aceeași fereastră produce exact aceleași rânduri. Se obține ștergând și reîncărcând partiția, sau prin merge pe cheie — niciodată prin adăugare oarbă, care dublează datele la a doua rulare. Cu ea, un backfill e doar o buclă peste ferestre vechi, iar o eroare de la 3 dimineața se rezolvă cu o reluare, nu cu o investigație. Încărcările incrementale poartă un watermark și o fereastră pentru datele care sosesc târziu; fișierele mici se compactează; totul se testează în CI, ca orice cod.
Ingineria datelor este dezvoltarea, implementarea și întreținerea sistemelor și proceselor care primesc date brute și produc informație de calitate, consistentă, care susține cazuri de utilizare din aval, precum analiza și învățarea automată.Fundamentals of Data Engineering (2022), cap. 1 — definiția ingineriei datelor
De ce contează Un pipeline care nu poate fi rerulat fără să dubleze datele transformă fiecare incident într-o operațiune manuală de curățenie.
Pe larg →Strânge ↑
Gândește-te la un pipeline ca la o funcție, nu ca la un eveniment unic. Dacă îi dai ca parametru o fereastră de timp, aceeași intrare produce mereu aceeași ieșire. Asta schimbă natura defecțiunilor. Un pipeline care adaugă orbește rânduri e ca un casier care tipărește bonul de două ori și încasează ambele sume. Unul idempotent e ca un formular online: poți apăsa trimite din nou, sistemul îți arată aceeași confirmare. Reparabilitatea devine atunci o decizie de design, nu o speranță. Iar dacă fiecare rulare e o funcție pură pe o fereastră, apare o întrebare firească: cine decide ordinea și momentul acestor apeluri?
Pasajul precedent s-a oprit la o întrebare: cine ordonează aceste apeluri? Răspunsul e orchestratorul. El ține graful sarcinilor, le declanșează când dependențele sunt gata și reia ce a picat. Detaliul esențial: el nu spune niciodată „rulează acum”, ci „rulează fereastra de ieri”. Așa o rulare eșuată poate fi repetată mâine cu aceeași intrare. Gândește-te la un panificator care coace pe comenzi, nu când i se pare: fiecare comandă are o dată, deci o comandă ratată de marți se poate coace miercuri, identică. Cu ferestre ca parametri, un backfill devine banal: aceeași rețetă, aplicată bucată cu bucată peste trecut. Rămâne de văzut ce garantează că repetarea nu strică ceva deja corect.
Pasajele anterioare au arătat cine ordonează rulările. Acum: ce mecanisme fac o rulare repetabilă în practică. Există două rețete principale. Prima: ștergi partiția ferestrei și o reîncarci de la zero, ca să înlocuiești o foaie dintr-un caiet, nu să lipești una peste alta. A doua: faci merge pe cheie, adică actualizezi rândurile existente și inserezi doar cele noi, ca un registru în care corectezi o linie, nu rescrii tot registrul. Ce e interzis e adăugarea oarbă, care dublează datele la a doua rulare. Mai rămâne o problemă: datele care sosesc târziu. De asta încărcarea incrementală poartă un watermark și o fereastră de întârziere, ca o cutie poștală care așteaptă scrisori după ce coșul a trecut. Dar cum verifici că toate aceste mecanisme chiar funcționează înainte de producție?
Repetabil și corect sunt lucruri diferite. O rulare poate produce aceleași rânduri de zece ori și tot să greșească. De aceea transformările se testează ca orice cod: aserțiuni care verifică dacă cheile sunt unice, dacă sumele se potrivesc, dacă niciun câmp obligatoriu nu e gol. Un test eșuat oprește pipeline-ul înainte ca datele proaste să ajungă la rapoarte. Gândește-te la controlul de calitate dintr-o fabrică de conserve: fiecare cutie e verificată înainte de etichetare, nu după ce e pe raft. Iar testele trăiesc în același depozit cu codul, rulate automat la fiecare schimbare, ca o rețetă care e gustată la fiecare modificare de ingredient. Așa reparabilitatea devine încredere verificată, nu promisiune. Rămâne o ultimă bucată: cine vede tot acest proces și cum își dă seama cineva ce s-a întâmplat la 3 dimineața.
Pasajele anterioare au acoperit mecanica. Rămâne ultima întrebare: cine ține transformarea vie? Când SQL-ul stă în depozitul de versiuni, granița dintre inginerul de date și analist se estompează. Inginerul asigură țevile: ferestre, idempotență, orchestrare. Analistul modelează sensul: ce e un client activ, ce înseamnă o vânzare. E ca într-o bucătărie: unul ține aragazul funcțional, celălalt decide rețeta, iar amândoi semnăază felul final. De aici apare nevoia de contracte de date: coloanele, tipurile și pragurile de calitate devin promisiuni scrise, pe care avalul le poate verifica. Un raport lunar de facturare nu mai pică liniștit pentru că cineva a redenumit o coloană; contractul strigă mai întâi. Asta închide cercul: pipeline-ul nu mai e o țeavă întreținută în tăcere, ci un produs cu utilizatori, promisiuni și un responsabil. Iar următorul pas al lecturii e să alegi unde se oprește transformarea ta.
Pasajele de până acum au tratat depozitul ca pe o cameră infinită. În practică, alegi unde se oprește transformarea și unde începe stocarea goală. Datele brute rămân intacte, deci cresc necontrolat: un magazin online care copiază fidel fiecare click ajunge la mii de fișiere mici pe zi, iar fiecare interogare le deschide pe toate. De asta se compactează periodic, ca să aranjezi o grămadă de bonuri mici într-un singur dosar lunar. Apare și întrebarea inversă: ce transformi în sursă, înainte de copiere? Regula practică: în sursă doar ce e prea voluminos sau prea sensibil, restul în depozit, unde e vizibil și testabil. Filtrarea jurnalelor de acces la graniță e ok; calcularea veniturilor acolo e o capcană, pentru că scapă de sub ochii tuturor. Următoarea întrebare e cine plătește toate aceste alegeri.
Parametrul unei rulări nu e niciodată „acum”, ci o fereastră de timp. Dacă pipeline-ul citește ora curentă, rularea de ieri nu mai poate fi repetată, pentru că „acum” s-a schimbat. Cu ferestre, o rulare e doar o funcție cu argumente: ianuarie 5 produce aceleași rânduri ori de câte ori o apeși. Asta transformă backfill-ul dintr-o operațiune eroică într-o buclă banală peste ferestre vechi, rulată în paralel. Gândește-te la un contabil care reface situația lunii martie: lucrează din cifrele din martie, nu din cele de azi. Apoi apare întrebarea firească: cât de des rulezi fiecare fereastră, și cine decide programul?
Pasajele au arătat ferestrele și testele. Rămâne mecanica concretă a idempotenței: cum faci o rulare repetabilă la nivel de rând. Două căi există. Prima: ștergi partiția ferestrei și o reîncarci de la zero. A doua: faci merge pe cheie, adică actualizezi rândul vechi dacă cheia există și inserezi doar dacă nu. Ambele produc aceleași rânduri la a doua rulare. Cea de-a treia cale, adăugarea oarbă, e capcana: un pipeline incremental care doar inserează va dubla comenzile de marți dacă rulează de două ori. Gândește-te la un coș de cumpărături: dacă clientul mai adaugă un produs, îi actualizezi coșul, nu îi creezi un coș nou lângă cel vechi. Dar merge-ul are o condiție: cheia trebuie să fie stabilă și completă. O cheie care se schimbă în timp, precum adresa unui client, transformă actualizarea în istorie pierdută. Atunci alegi conștient: rând curent sau istorie cu valabilitate. Iar alegerea cheii decide dacă pipeline-ul tău poate fi reparat sau doar curățat manual.
Idempotența nu e o virtute la care speri, ci o proprietate pe care o verifici. Iei aceeași fereastră, rulezi de două ori, și compari rezultatul: identic sau nu. Cea mai simplă metodă e ștergerea și reîncărcarea partiției, ca să înlocuiești o foaie dintr-un caiet, nu să lipești alta peste. Când reîncărcarea completă e prea scumpă, folosești merge pe cheie: rândul nou înlocuiește vechiul, nu i se adaugă lângă. Adăugarea oarbă pare mai rapidă, dar a doua rulare dublează vânzările din martie, iar un raport de venituri devine mincinos fără să pară stricat. De asta testul de idempotență stă în integrarea continuă, lângă testele de cod. Cum îl aplici totuși la volume uriașe, unde reîncărcarea completă costă prea mult?
Deschide pe YouTube ↗ - 14
Lecția 14 · Calitatea se construiește în pipeline, nu se inspectează în raport.
Out of the Crisis · W. Edwards Deming · 1986
Calitatea datelor are dimensiuni care se pot măsura: completitudine (lipsesc rânduri sau valori?), unicitate (chei duplicate?), validitate (valori din setul permis, tipuri corecte), consistență (totalul liniilor egal cu totalul comenzii?), actualitate (au sosit la timp?) și acuratețe (corespund realității?). Punctul lui Deming aplicat aici: testele sunt cod și stau lângă transformări, nu într-un raport de audit trimestrial. La intrare, contracte (lecția 12). Pe fiecare model: not null, unic, valori acceptate, relații între tabele, prospețime, volum așteptat. La ieșire, monitoare de anomalie pe cifrele care contează — numărul de rânduri pe zi, distribuțiile, sumele. Ce faci când un test pică depinde de ce e în joc: pentru cifre critice, încărcarea se oprește (fail-closed) și cineva se uită; pentru rest, rândurile suspecte merg în carantină și restul trece. Fiecare set de date are un proprietar și un SLA, iar cauza se repară în amonte, nu în raport. Raportul e locul unde afli; nu e locul unde repari.
Încetați să depindeți de inspecție pentru a obține calitate. Eliminați nevoia de inspecție în masă construind calitatea în produs de la bun început.Out of the Crisis (1986), cap. 2 — cele 14 puncte pentru management, punctul 3
De ce contează Aceeași eroare costă o linie de test la intrare și o săptămână de reconciliere când e găsită în raport. Diferența e locul, nu efortul.
Pe larg →Strânge ↑
Calitatea nu e doar construită în pipeline; pipeline-ul poate învăța. Fiecare rând carantinat e un semnal, nu doar gunoi de aruncat. Dacă aceeași verificare pică des, contractul de la intrare e prea slab și merită strâns. Astfel testul de ieri devine regula de azi, iar inspecția se mută tot mai devreme, până dispare aproape. Gândește-te la un magazin care primește facturi electronice. Prima dată, un total greșit e prins de un test și rândul merge în carantină. După a treia oară, adaugi în contract regula că totalul trebuie să corespundă liniilor, iar furnizorul e notificat. Luna următoare, eroarea nu mai ajunge deloc în sistem. Asta schimbă rolul echipei de date: mai puțin detectiv, mai mult arhitect de reguli. Raportul devine istoric, nu alarmă. Pasul următor e să întrebi cine are autoritatea să strângă contractul — și ce se întâmplă când furnizorul refuză.
Deschide pe YouTube ↗ - 15
Lecția 15 · Gunoi la intrare, gunoi la ieșire — iar proveniența e singurul mod de a afla pe unde a intrat gunoiul.
Passages from the Life of a Philosopher · Charles Babbage · 1864
Întrebarea care l-a scos din sărite pe Babbage e pusă și azi, doar că altfel: „modelul e bun, deci cifrele sunt bune?”. Nu. Un depozit nu repară ce primește; cel mult face vizibil de unde a venit. Asta e proveniența (lineage): pentru fiecare cifră dintr-un raport, drumul înapoi prin transformări până la rândurile și fișierul sursă, la nivel de coloană, dedus din SQL-ul care le-a produs. Pe fiecare rând, metadate mici: sistemul sursă, identificatorul încărcării, momentul extragerii. La ce folosește: analiza de impact (dacă sursa X se strică, ce rapoarte suferă?), depanarea (cifra asta ciudată — din ce rânduri? din ce fișier? din ce zi?), conformitatea (pe unde circulă datele personale, lucru pe care GDPR îl cere explicit) și reproductibilitatea (același cod, aceeași versiune de date, același rezultat). Cazul tipic: o coloană de sumă trece în amonte din lei în euro fără anunț; totalurile „arată plauzibil” două săptămâni. Nicio validare de tip nu prinde asta. Singura apărare e să poți urmări fiecare cifră înapoi și să vezi ziua în care distribuția s-a mutat.
De două ori am fost întrebat: «Vă rog, domnule Babbage, dacă introduceți în mașină cifre greșite, vor ieși răspunsurile corecte?» … Nu sunt în stare să pricep ce fel de confuzie a ideilor ar putea provoca o asemenea întrebare.Passages from the Life of a Philosopher (1864), cap. V — Difference Engine No. 1
De ce contează Cifra greșită care „arată bine” e cea mai scumpă din depozit. Fără proveniență, o cauți săptămâni; cu ea, o găsești într-o interogare.
Pe larg →Strânge ↑
Proveniența nu se reconstruiește după dezastru; se scrie în momentul în care datele se mișcă. Dacă aștepți până când un total arată ciudat, va trebui să ghicești drumul parcurs. Dacă fiecare transformare își lasă urma din start, interogarea e deja gata. Gândește-te la un apartament închiriat: proprietarul care fotografiază fiecare cameră la predare rezolvă orice dispută în cinci minute. Cel care nu o face își amintește „cam așa arăta”. Diferența nu e tehnologia, ci disciplina de a nota la momentul potrivit. Următorul pas e să vezi cine ar trebui să poarte această responsabilitate.
Deschide pe YouTube ↗ - 16
Lecția 16 · Pregătirea datelor pentru ML: același depozit, dar cu timpul corect, fără scurgeri și cu trăsături reproductibile.
The Unreasonable Effectiveness of Data · Alon Halevy, Peter Norvig, Fernando Pereira · 2009
Argumentul din 2009 a devenit doctrină: mai multe date bat un model mai deștept. Condiția nespusă e că datele sunt corecte în trei feluri pe care un depozit de raportare nu le cere. Întâi, corectitudinea în timp: o trăsătură (feature) se calculează „așa cum era la momentul evenimentului”, nu „așa cum e acum” — un client care azi e premium era, poate, gratuit când a făcut comanda din 2023; dimensiunile de tip 2 sunt exact ce trebuie aici. Apoi, scurgerea (leakage): o coloană care conține răspunsul, direct sau indirect — data anulării când prezici anularea; modelul pare excelent la antrenament și eșuează în producție. În fine, decalajul antrenament–servire (skew): trăsăturile calculate în batch pentru antrenament și cele calculate live pentru predicție trebuie să vină din același cod; feature store-ul există ca să garanteze asta. Restul e disciplină de depozit: împarți seturile pe timp, nu la întâmplare; documentezi definiția etichetei; versionezi setul de antrenament ca să-l poți reproduce peste un an; păstrezi echilibrul claselor în minte. Abia atunci „multe date” înseamnă mai mult decât „multe rânduri”.
Dar, invariabil, modelele simple și multe date bat modelele mai elaborate bazate pe mai puține date.The Unreasonable Effectiveness of Data, IEEE Intelligent Systems 24(2), 2009
De ce contează Un model antrenat pe trăsături „de azi” pentru evenimente „de atunci” învață viitorul și îl uită în producție. Depozitul trebuie să știe să răspundă „cum era la momentul acela”.
Pe larg →Strânge ↑
Cardul spune ce trebuie să îndeplinească datele. Pasul următor e cine garantează asta. Niciun analist nu ține minte manual că un client era gratuit în 2023. Corectitudinea în timp nu e o virtute personală, ci o proprietate a infrastructurii: sistemul trebuie să poată reconstrui trecutul așa cum era, nu așa cum îl știm azi. Gândește-te la un magazin online care recalculează istoricul comenzilor după ce schimbă regulile de discount — toate predicțiile vechi devin neînsenelnicioase. De aceea echipele serioase tratează setul de antrenament ca pe un produs, cu proprietar, versiune și definiție scrisă. Întrebarea practică devine: dacă te întreb azi „ce știa modelul în martie trecut?”, cine îți răspunde în cinci minute? Pasul următor e ce se întâmplă când nimeni nu poate.
Pasajul 1 a vorbit despre cine garantează corectitudinea în timp. Dar există o greșeală mai insidioasă, pe care nicio infrastructură nu o prinde automat: scurgerea. O coloană poate conține răspunsul pe care vrei să-l prezici, uneori deghizat. Prezici anularea abonamentului și, fără să-ți dai seama, incluzi data ultimei plăți eșuate — un semnal care apare abia după ce decizia de anulare e luată. Modelul pare genial în testare și se prăbușește în producție. Exemplul de zi cu zi: la un spital, istoricul de medicație administrată după diagnostic trădează diagnosticul. Scurgerea nu se vede în cifre, ci doar în întrebarea: când a fost valabilă informația asta? Apoi mai rămâne decalajul dintre antrenament și servire — codul care calculează trăsăturile offline trebuie să fie același cu cel online. Cum poți testa sistematic dacă ceva scurge?
Deschide pe YouTube ↗ - 17
Lecția 17 · Embeddings: sensul devine un vector, iar depozitul primește o coloană pe care nu o poate compara cu «=».
A synopsis of linguistic theory 1930–1955 · John Rupert Firth · 1957
Ideea lui Firth, formalizată: un model citește un text și îl transformă într-un vector de câteva sute sau mii de numere, astfel încât texte cu sens apropiat ajung vectori apropiați. Apropierea se măsoară — de obicei cosinus — nu se verifică prin egalitate. De aici o structură nouă în depozit: indexul vectorial (HNSW, IVF), care găsește aproximativ cei mai apropiați vecini fără să compare cu fiecare rând. Peste el stă RAG: caută fragmentele relevante după sens, apoi lasă un model generativ să răspundă folosindu-le. Ce se schimbă pentru inginerul de date: versiunea modelului de embedding face parte din schemă — schimbi modelul, recalculezi coloana, altfel compari vectori din spații diferite. Se stochează lângă vector: textul, un hash al lui, modelul, dimensiunea. Fragmentarea (chunking) e o decizie de modelare, nu un detaliu. Filtrele pe metadate (limbă, dată, client) se aplică înainte sau împreună cu căutarea vectorială, nu după. Și vectorii nu înlocuiesc cheile și join-urile: sunt o coloană în plus într-un tabel care rămâne relațional.
Vei cunoaște un cuvânt după compania pe care o ține.A synopsis of linguistic theory 1930–1955, în Studies in Linguistic Analysis (1957)
De ce contează Un depozit care nu știe ce model a produs un vector nu poate spune dacă doi vectori sunt comparabili. Coloana fără versiune e o coloană fără sens.
Pe larg →Strânge ↑
Firth a spus că sensul unui cuvânt e compania în care apare. Modelele de embedding au făcut asta literal: sensul devine o poziție în spațiu. Dar poziția apropiată nu înseamnă răspuns corect. Doi vectori pot fi vecini și tot să nu-ți folosească la nimic. De exemplu, cauți «cum anulez un bilet» și primești un fragment despre politicile de anulare ale altei companii. E semantic aproape, dar greșit pentru tine. De aceea căutarea vectorială trebuie evaluată, nu doar rulată. Întrebarea deschisă: cum măsori dacă fragmentele găsite sunt chiar cele potrivite?
Deschide pe YouTube ↗ - 18
Lecția 18 · Separă identitatea de fapte: un seif de identități, un token în depozit și nicio cale înapoi fără cheie.
Regulamentul general privind protecția datelor (GDPR) · Parlamentul European și Consiliul Uniunii Europene · 2016
Definiția din regulament e, citită ca arhitectură, o schemă cu trei părți. Seiful de identitate: nume, e-mail, cod numeric personal, adresă — criptat, cu acces restrâns, în propriul lui sistem. Harta de tokeni: legătura dintre persoană și un pseudonim, fie un surogat aleatoriu, fie un HMAC cu o cheie secretă; un simplu hash al e-mailului nu ajunge, se inversează cu un dicționar. Depozitul: faptele, cheiate pe token. Analiștii văd tokeni și comportamente, niciodată identități; join-ul înapoi e posibil doar pentru cine are cheia, și e auditat. Ce câștigi: ștergerea unei persoane devine ștergerea rândului din seif — faptele rămân, dar nu mai duc la nimeni; accesul la identitate se acordă separat de accesul la analiză; „unde sunt datele acestei persoane” se răspunde din proveniență (lecția 15). Ce nu câștigi: datele pseudonimizate rămân date personale, fiindcă informația suplimentară există. Toate obligațiile rămân; riscul scade. Anonimizarea reală e alt prag, cu propriile ei capcane — lecția 20.
«pseudonimizare» înseamnă prelucrarea datelor cu caracter personal într-un asemenea mod încât acestea să nu mai poată fi atribuite unei anume persoane vizate fără a se utiliza informații suplimentare, cu condiția ca aceste informații suplimentare să fie stocate separat și să facă obiectul unor măsuri de natură tehnică și organizatorică care să asigure neatribuirea respectivelor date cu caracter personal unei persoane fizice identificate sau identificabileRegulamentul (UE) 2016/679, art. 4 pct. 5
De ce contează Un depozit cu numele pe fiecare rând nu poate șterge o persoană fără să rescrie istoricul. Unul cu tokeni o șterge dintr-un singur rând, în altă cameră.
Pe larg →Strânge ↑
Gândește la cheia ca la un rol, nu la un obiect. Cine o deține nu ar trebui să lucreze niciodată în depozit, iar analiștii nu ar trebui să o vadă vreodată. Separarea asta schimbă ce înseamnă o scurgere de date. Dacă cineva fură tabelul cu fapte, fură doar comportamente legate de tokeni — fără nume, fără e-mailuri, fără cod numeric. Un program de fidelitate, de pildă, poate lăsa echipa de marketing să vadă cine cumpără ce, sub pseudonim, fără ca nimeni din echipă să știe cui îi aparține coșul. Furtul devine incomplet prin construcție, nu doar prin noroc. Dar asta ridică o întrebare practică: cine, anume, ar trebui să țină cheia în organizația ta?
Deschide pe YouTube ↗ - 19
Lecția 19 · Datele personale sunt un pasiv: inventariază-le, colectează minim, păstrează cu termen și șterge demonstrabil.
Data Is a Toxic Asset, So Why Not Throw It Out? · Bruce Schneier · 2016
Schneier răstoarnă intuiția „datele sunt petrolul nou”: ce nu ai nu ți se poate fura, nu ți se poate cere în instanță și nu trebuie să explici de ce l-ai păstrat. Pentru depozit, asta devine un ciclu cu patru etape. Inventar: unde sunt coloanele cu date personale, marcate prin clasificare (direct identificatoare, cvasi-identificatoare, sensibile), descoperite automat pe cât se poate. Minimizare: colectezi doar ce servește un scop declarat; o dată de naștere completă când ai nevoie de grupa de vârstă e o coloană de prisos. Retenție: fiecare set are un termen și un motiv, iar ștergerea e un job programat, nu o promisiune. Ștergere: demonstrabilă, inclusiv din copii de siguranță și din date derivate. Și aici se împacă imutabilitatea (lecția 10) cu dreptul la ștergere: crypto-shredding. Datele fiecărei persoane se criptează cu propria ei cheie; ștergerea persoanei înseamnă distrugerea cheii. Rândurile rămân fizic în fișierele imuabile și în backup-uri, dar nu se mai pot citi de nimeni, niciodată. Un log care nu se poate rescrie și o ștergere care nu se poate anula, deodată.
Datele sunt un activ toxic. Trebuie să începem să le gândim așa și să le tratăm cum am trata orice altă sursă de toxicitate.Data Is a Toxic Asset, So Why Not Throw It Out? — eseu, CNN / schneier.com, martie 2016
De ce contează Fiecare coloană cu date personale pe care nu o folosești e risc fără beneficiu. Costul ei nu se vede în factura de stocare, ci în ziua incidentului.
Pe larg →Strânge ↑
Un depozit care aplică deja minimizarea și retenția mai are o problemă: datele vechi nu dispar singure. Schneier mută deci responsabilitatea din politici în cod. O regulă scrisă într-un document poate fi ignorată; un job programat care rulează săptămânal nu. Diferența nu e tehnică, ci de dovadă. Când un regulator sau un client întreabă „ce ați șters și când”, răspunsul corect nu e o promisiune, ci un jurnal de execuție. Gândește-te la frigiderul de acasă: nu e suficient să decizi să arunci laptele expirat; trebuie să te uiți efectiv în el în fiecare duminică. La fel, ștergerea demonstrabilă transformă igiena datelor dintr-o intenție într-un fapt verificabil. Pasul următor e să vezi ce se întâmplă când coloanele pe care le-ai păstrat totuși ajung în fișiere imuabile, unde nu poți șterge nimic fizic.
Pasajul precedent s-a încheiat exact la punctul blocant: fișierele imuabile și backup-urile nu permit ștergere fizică. Aici crypto-shredding schimbă sensul cuvântului „șters”. Fiecare persoană primește o cheie proprie de criptare, iar datele ei se scriu criptat cu ea. Rândurile rămân în fișier, dar cheia e singura ușă. Distrugi cheia și datele devin zgomot pentru oricine, pentru totdeauna. Ștergerea nu mai înseamnă să cauți copii prin backup-uri, ci un singur act: nimicirea unei chei. E ca o casă sigură pe care nu o poți demola, dar al cărei singur cheie poți s-o arunci în râu. Un log imuabil și o ștergere ireversibilă, deodată. Rămâne o întrebare practică: ce faci când cheile și datele nu stau la același custode?
Deschide pe YouTube ↗ - 20
Lecția 20 · Fără nume nu înseamnă anonim: codul poștal, data nașterii și sexul identifică majoritatea oamenilor.
k-anonymity: a model for protecting privacy · Latanya Sweeney · 2002
Sweeney a arătat, cu date reale de spital „anonimizate” și o listă electorală cumpărată, că trei coloane banale — codul poștal, data nașterii și sexul — sunt unice pentru cea mai mare parte a populației. Coloanele astea sunt cvasi-identificatori: fiecare e inofensivă singură, împreună sunt un nume. k-anonimitatea e răspunsul ei: publicarea e sigură doar dacă fiecare combinație de cvasi-identificatori apare la cel puțin k persoane. Se obține prin generalizare (data nașterii devine an sau grupă de vârstă, codul poștal devine județ) și suprimare (rândurile prea rare se scot). Nu e sfârșitul poveștii. Dacă toți cei k dintr-un grup au același diagnostic, tot ai aflat ceva despre fiecare — de aici l-diversitatea și t-apropierea, care cer varietate în atributul sensibil. Și orice set „anonim” poate fi legat cu un alt set publicat mâine. Pentru depozit, regula practică: un extras fără nume nu e anonim până nu i-ai numărat cvasi-identificatorii și nu ai verificat k pe fiecare combinație; iar agregarea e prietena ta — un raport pe grupe de vârstă și județ nu are rânduri de persoane deloc.
O publicare oferă protecție de tip k-anonimitate dacă informația despre fiecare persoană conținută în publicare nu poate fi deosebită de cea a cel puțin k-1 alte persoane ale căror informații apar, de asemenea, în publicare.k-anonymity: a model for protecting privacy, International Journal of Uncertainty, Fuzziness and Knowledge-Based Systems 10(5), 2002 — rezumat
De ce contează Extrasul „fără nume” trimis unui partener e cea mai des întâlnită scurgere de date personale și cea mai rar recunoscută ca atare.
Pe larg →Strânge ↑
k-anonimitatea nu e o proprietate a fișierului, ci a lui față de restul lumii. Aceeași coloană fără nume poate fi sigură într-o țară și periculoasă într-un sat. Să zicem că publici un extras cu vârstă, sex și localitate. Într-o municipalitate mare, combinația acoperă zeci de oameni. Într-o comună mică, același extras poate fi unic pentru un singur locuitor. Deci k-ul nu se măsoară în fișier, ci în populația cu care fișierul poate fi îmbinat. Cine primește extrasul contează la fel de mult ca ce conține el. Un partener care deține alte liste îți schimbă singur k-ul, fără să atingi fișierul. Întrebarea practică nu e „am scos numele?”
Pasajul 1 a arătat că k-ul depinde de cine primește fișierul. Pasul următor: generalizarea costă ceva, și alegerea costului e o decizie, nu o formulă. Dacă transformi data nașterii în an, pierzi precizia. Dacă o transformi în grupă de vârstă, pierzi și mai mult. La fel cu codul poștal: județul acoperă mai mulți oameni decât orașul. Fiecare pas de generalizare face fișierul mai greu de identificat, dar și mai greu de folosit. Un medic care vrea să studieze o boală rară la tineri nu poate lucra cu grupe de vârstă largi. Deci trebuie să negociezi: cât k e suficient, și cât de multă precizie poți să sacrifici pentru el. Nu există un răspuns universal — există doar un echilibru ales conștient, cu cineva care poartă responsabilitatea alegerii. Dar ce se întâmplă când chiar și acel echilibru e atins și tot rămâne o scurgere?
Deschide pe YouTube ↗ - 21
Lecția 21 · Confidențialitatea diferențială: adaugi zgomot calibrat la răspuns, nu la date, și promisiunea rezistă la orice alt set publicat.
The Algorithmic Foundations of Differential Privacy · Cynthia Dwork, Aaron Roth · 2014
Slăbiciunea k-anonimității e că depinde de ce altceva există în lume. Confidențialitatea diferențială schimbă întrebarea: nu „poate fi reidentificat setul?”, ci „se schimbă răspunsul la o interogare dacă o singură persoană intră sau iese din set?”. Dacă răspunsul e aproape același cu sau fără tine, nimeni nu învață nimic despre tine anume, orice ar mai ști. Mecanismul: la fiecare răspuns agregat (o sumă, o medie, un număr) se adaugă zgomot aleatoriu calibrat la cât poate mișca un singur individ rezultatul. Parametrul epsilon e bugetul: mai mic înseamnă mai multă protecție și mai puțină precizie, iar fiecare interogare consumă din el — după ce bugetul s-a terminat, nu mai răspunzi. Pentru depozit e o tehnică de ieșire, nu de stocare: datele brute rămân întregi și protejate ca în lecțiile 18–19; ce se protejează e ce pleacă spre exterior — statistici publice, rapoarte către parteneri, seturi de antrenament. Recensămintele moderne o folosesc exact așa. Costul e real și trebuie spus utilizatorilor: pe grupuri mici, zgomotul e comparabil cu semnalul.
„Confidențialitatea diferențială” descrie o promisiune făcută de deținătorul datelor, sau curator, persoanei vizate: „Nu vei fi afectat, negativ sau altfel, dacă permiți ca datele tale să fie folosite în orice studiu sau analiză, indiferent ce alte studii, seturi de date sau surse de informație există.”The Algorithmic Foundations of Differential Privacy (2014), cap. 1 — The Promise of Differential Privacy
De ce contează E singura definiție a confidențialității care nu se prăbușește când apare mâine un alt set de date. Prețul e precizia, iar prețul trebuie spus.
Pe larg →Strânge ↑
Pasajul 1. Zgomotul se pune pe răspuns, nu pe date, și asta schimbă cine trebuie să aibă încredere în cine. Nu mai depinzi de bunăvoința analistului care primește statistica: promisiunea e construită în rezultatul publicat, înainte să plece din depozit. Analistul poate fi oricine, cu orice alte date la îndemână, și tot nu poate izola contribuția ta. Gândește-te la un buletin de vot: nimeni nu vede ce ai bifat, doar totalul, iar totalul nu-ți trădează alegerea. Următorul pas: ce se întâmplă când nu răspunzi o singură dată, ci de multe ori la aceleași date.
Fiecare răspuns consumă din aceeași rezervă de confidențialitate. O singură statistică zgomotoasă e inofensivă, dar zece, puse cap la cap, pot reconstrui ce voiai să rămână ascuns. De asta bugetul există: epsilon e o limită pe care curatorul o alege înainte, nu după. E ca un cont cu retrageri — poți întreba de câte ori vrei, dar fiecare retragere scade soldul, iar când ajunge la zero, nu mai răspunzi. Alegerea e a ta, nu a analistului care bate la ușă. Practic, asta înseamnă că un raport public trebuie planificat: ce statistici ies, cu ce precizie, în ce ordine. Un spital, de pildă, decide din start câte luni publică statistici pe vârste și câte zgomot acceptă pe fiecare. Rămâne o întrebare deschisă: cine și cum decide cât zgomot e suficient pentru societate?
Deschide pe YouTube ↗ - 22
Lecția 22 · Depozitul e cea mai mare țintă din firmă fiindcă adună totul; apărarea e privilegiul minim, aplicat pe rânduri și coloane, cu audit.
The Protection of Information in Computer Systems · Jerome Saltzer, Michael Schroeder · 1975
Un sistem sursă expune un client; depozitul îi expune pe toți, cu istoric. De aceea principiul din 1975 e aici mai concret decât oriunde. Privilegiul minim se aplică pe trei axe: tabele (un rol vede doar schemele de care are nevoie), coloane (mascare dinamică: analistul vede ultimele patru cifre, contabilitatea vede tot) și rânduri (securitate la nivel de rând: un agent de vânzări vede doar regiunea lui, prin aceeași vedere, fără copii ale tabelului). Accesul la seiful de identitate din lecția 18 e un rol separat, acordat separat. Dedesubt, două straturi care nu se negociază: criptare în repaus, cu chei administrate în afara depozitului și rotite, și criptare în tranzit. Deasupra, auditul: fiecare interogare pe tabelele sensibile e înregistrată — cine, când, ce a citit, câte rânduri — păstrată și, mai ales, citită de cineva. Capcanele obișnuite sunt banale și de aceea frecvente: un cont de serviciu pentru instrumentul de BI cu drepturi pe tot depozitul, folosit de toți; secrete lipite în SQL; conturi partajate care fac auditul inutil. Regula lui Saltzer și Schroeder, citită invers: orice privilegiu pe care nu-l poți justifica printr-o sarcină e unul de scos.
Fiecare program și fiecare utilizator al sistemului ar trebui să opereze folosind cel mai mic set de privilegii necesar pentru a-și îndeplini sarcina.The Protection of Information in Computer Systems, Proceedings of the IEEE 63(9), 1975 — §I.A.3, principiul (f), least privilege
De ce contează Un singur cont de serviciu supra-privilegiat transformă o breșă într-un instrument de raportare într-o scurgere a întregului istoric al firmei.
Pe larg →Strânge ↑
Cardul acoperă cele trei axe: tabele, coloane, rânduri. Pasul următor e timpul. Un privilegiu poate fi minim la o oră și excesiv la alta. De aceea accesul larg la depozit ar trebui să fie temporar: ridici drepturile pentru o fereastră scurtă, faci lucrarea, apoi ele expiră singure. Exemplul de zi cu zi: nimeni nu împrumută cheia de la casă toată ziua; o ceri la plată și o predai imediat. La fel, un inginer cere acces de citire la tabelul de salarii doar pentru sesiunea de depanare de marți. Contul permanent larg devine excepția, nu regula. Astfel auditul capătă sens: înregistrarea arată nu doar cine a citit ce, ci și de ce avea dreptul în acel moment. Dar temporaritatea ridică o întrebare nouă: cine are voie să acorde aceste ferestre de acces?
Pasajul 1 s-a oprit la întrebare: cine acorde ferestrele de acces? Răspunsul din 1975 e separarea sarcinilor. Persoana care cere acces nu trebuie să fie cea care îl aprobă, iar cea care aprobă nu trebuie să fie cea care verifică apoi. Într-o firmă mică asta pare exagerat, dar funcționează simplu: dezvoltatorul cere acces, lead-ul echipei aprobă, iar raportul de audit ajunge lunar la securitate. Trei ochi diferiți, nu unul. Exemplul de zi cu zi: la bancă, cel care deschide seiful nu e cel care numără banii. La fel, în depozit, un cont de serviciu nu ar trebui să-și poată extinde singur drepturile. Dacă același om cere, acordă și verifică, privilegiul minim devine doar un formular semnat de el însuși. Dar aprobarea e doar jumătate din mecanism — ce se întâmplă când cineva abuzează totuși de accesul primit?
Deschide pe YouTube ↗ - 23
Lecția 23 · Cloud sau on-prem nu e o întrebare despre loc, ci despre cine operează ce și cât costă la gol față de vârf.
All Things Distributed · Werner Vogels · 2008
În cloud, calculul e separat de stocare și elastic: plătești pe secundă sau pe interogare, nu cumperi hardware, actualizările sunt ale furnizorului, regiunile sunt la un click. Reversul: costul de ieșire a datelor (egress), interogări nemărginite care produc facturi surpriză, dependența de furnizor și rezidența datelor, care pentru date reglementate cere regiune europeană și chei administrate de tine. On-prem: cost previzibil la sarcină constantă, control complet, latență mică spre sistemele interne, date sensibile care nu pleacă. Reversul: planificare de capacitate (plătești vârful tot anul), actualizări, oameni, un singur amplasament. Decizia se ia pe câteva variabile, nu pe modă: cât de variabilă e sarcina, ce cere reglementarea, ce știe echipa, ce licențe există deja, cât iese pe egress. Hibridul e legitim: seiful de identitate acasă, faptele pe token în cloud. Iar fraza lui Vogels e valabilă în ambele locuri: discul cedează și în centrul tău de date, furnizorul are și el pene. Deci copii de siguranță testate prin restaurare, nu prin existență; exerciții de refacere; două zone. „Unde” e întrebarea mică; „ce se întâmplă când cedează” e cea mare.
Orice lucru cedează, tot timpul.Werner Vogels — formulare reluată în prezentări și pe blogul All Things Distributed, din 2008
De ce contează Factura cloud crește cu fiecare interogare neglijentă; factura on-prem e fixă și include vârful pe care îl atingi o zi pe an. Ambele se pierd dacă nu ai testat o restaurare.
Pe larg →Strânge ↑
Cardul spune că decizia se ia pe variabile, nu pe modă. Hai să luăm una dintre ele și să o întoarcem pe toate fețele: profilul sarcinii. O firmă de contabilitate are trafic uriaș trei luni pe an și aproape zero restul. În cloud, plătește doar când lucrează. În propriul centru de date, ar cumpăra mașini puternice care stau goale nouă luni. Dar inversează exemplul: un spital cu sarcină constantă, nonstop, plătește în cloud aceeași factură în fiecare lună, la nesfârșit. La un moment dat, suma depășește prețul hardware-ului propriu. Deci nu există răspuns corect universal, există răspuns corect pentru forma încărcăturii tale. Întrebarea practică: desenează-ți curba de trafic pe un an și pune-o lângă ambele facturi. Apoi apare o a doua întrebare, pe care profilul singur nu o rezolvă: ce spune legea despre unde pot sta datele tale?
Pasajul 1 a lăsat întrebarea legii în aer. Hai să o luăm. Unele date nu au voie să plece din țară sau din Uniune: dosare medicale, date bancare, arhive publice. Atunci cloudul nu e interzis, dar devine condiționat: regiune europeană, chei pe care doar tu le țineți, contract care garantează unde stau lucrurile. Exemplu concret: un cabinet stomatologic vrea backup automat în cloud, dar datele pacienților trebuie să rămână în UE, deci alege o regiune europeană și verifică asta în contract, nu în broșură. Iar aici apare capcana pe care nimeni nu o pune în foaia de calcul: ieșirea datelor. Să intri e ieftin; să le scoți, să migrezi spre alt furnizor, costă. Furnizorul știe asta și prețul e făcut tocmai ca să nu pleci. Decizia de azi devine o ușă mai îngustă mâine. Dar chiar și cu legea mulțumită și prețul clar, mai lipsește ceva: cine, concret, operează totul?
A treia variabilă e cea mai umană: cine operează ce. În cloud, actualizările, penele hardware și securitatea de bază sunt ale furnizorului. Echipa ta trebuie doar să folosească serviciul bine. În propriul centru de date, cineva trebuie să aplice patch-uri, să schimbe discuri, să fie de gardă noaptea. Un restaurant cu trei angajați nu are cine să țină un server viu; un banc cu echipă de infrastructură, da. Deci întreabă-te sincer ce știe echipa, nu ce ar vrea să știe. Iar oricine operează orice, undeva, se lovesește de aceeași realitate: lucrurile cedează. De aceea următorul pas nu e alegerea locului, ci testul care supraviețuiește oricărei alegeri: restaurarea.
Pasajul 3 s-a terminat cu testul restaurării. Hai să-l facem concret. O copie de siguranță neverificată e doar o speranță, nu un plan. Testul real e simplu: ia backupul, refă sistemul într-un mediu curat, cronometrează cât durează și notează ce lipsește. O librărie online își descoperă astfel că backupul există, dar listele de produse se refac în trei zile, iar asta omoară vânzările de sărbători. De aici două obiceiuri: exerciții de refacere la interval regulat, nu o dată pe an din obligație, și copii în două locuri separate, pentru că nici furnizorul, nici centrul tău de date nu sunt imuni la pene. Aici se leagă totul: dacă ai testat restaurarea, ai deja datele ca să alegi între cloud, on-prem sau un amestec al lor. Următorul pas e să te uiți la acel amestec, hibridul, fără să-l tratezi ca pe un compromis de frică.
Pasajele de până acum au tratat hibridul ca pe o sinteză. Hai să-l vedem ca pe o decizie proprie, cu reguli clare. Ideea: separi datele după sensibilitate și după ritm, nu după modă. Identitățile, cheile, arhiva legală stau acasă, sub controlul tău. Sarcinile variabile, analizele, site-ul public merg în cloud, unde plătești pe consum. Un exemplu obișnuit: o firmă de arhitectură ține planșetele semnate și contractele pe un server propriu, dar redă randările 3D în cloud doar în săptămânile cu termene. Niciun compromis de frică, ci fiecare lucru acolo unde se descurcă cel mai bine. Dar hibridul aduce o factură nouă pe care mulți o descoperă târziu: traficul între cele două lumi costă la fiecare trecere. Un sync neglijent, rulat noaptea pe tot volumul, poate depăși costul mașinii proprii. Întrebarea care se deschide: cine, în organizația ta, citește factura înainte să devină surpriză?
Pasajul anterior s-a oprit la întrebarea: cine citește factura? Hai să ducem asta mai departe. Costul nu e un rezultat pe care îl primești, ci o variabilă de design, la fel ca securitatea. În cloud, fiecare alegere tehnică are un preț: cât deschezi o interogare, cât timp rulează o mașină, cât trafic scoți. O firmă de curierat lasă un raport să se regenereze la fiecare oră pe toate livrările; nimeni nu-l citește între două. Fiecare rulare e mică, suma nu e. Deci întrebarea nu e doar cine citește factura, ci cine decide înainte ce merită rulat. Un buget cu alerte, o regulă simplă de tip «rapoartele mari rulează noaptea, manual», un om numit prin nume, nu prin funcție. La fel cum testul restaurării e exercițiul pentru cedare, controlul costului e exercițiul pentru vârf. Următorul pas e să vedem ce se întâmplă când cele două eșuează odată.
Deschide pe YouTube ↗ - 24
Lecția 24 · Un join se execută în trei feluri, iar cele 3% critice ale lui Knuth sunt, într-un depozit, aproape întotdeauna un join.
Structured Programming with go to Statements · Donald Knuth · 1974
Trei algoritmi. Nested loop: pentru fiecare rând dintr-o parte, caută în cealaltă — imbatabil când o parte e minusculă sau cealaltă e indexată pe cheie, dezastruos între două tabele mari. Hash join: construiește o tabelă hash din partea mai mică, apoi trece o singură dată prin partea mare și potrivește — calul de povară al depozitului, cu condiția ca partea mică să încapă în memorie; dacă nu, se varsă pe disc și devine de zece ori mai lent. Merge join: ambele părți sortate pe cheie, o singură trecere paralelă — perfect când datele sunt deja ordonate. Planificatorul alege dintre ele pe baza statisticilor; statistici vechi înseamnă plan greșit, deci actualizarea lor e întreținere, nu opțiune. În sistemele distribuite se adaugă o întrebare: unde se întâlnesc rândurile? O dimensiune mică se difuzează (broadcast) pe toate nodurile; două tabele mari se redistribuie (shuffle) după cheie, iar o cheie fierbinte — adesea NULL — trimite jumătate din date pe un singur nod. Și capcana clasică: join-ul pe o cheie neunică multiplică rândurile, tăcut; dimensiunea de tip 2 din lecția 11 e exemplul tipic. Înainte de a optimiza, citește planul. Cele 3% sunt acolo, cu nume.
Ar trebui să uităm de micile eficiențe, să zicem cam 97% din timp: optimizarea prematură e rădăcina tuturor relelor. Și totuși n-ar trebui să ratăm ocaziile din acele critice 3%.Structured Programming with go to Statements, ACM Computing Surveys 6(4), 1974
De ce contează Nouă interogări din zece nu contează; a zecea ține tot raportul de dimineață, și în ea e un join care se varsă pe disc sau multiplică rânduri.
Pe larg →Strânge ↑
Un plan bun nu e o proprietate a interogării, ci a momentului. Același join poate fi nested loop luna trecută și hash join astăzi, pentru că datele au crescut. Gândește-te la lista de prețuri: când avea o mie de rânduri, căutarea rând cu rând era instant. După cinci ani de produse, același plan înghite minute. De aceea o interogare „care mergea mereu” nu e un argument — e doar o fotografie veche. Planificatorul nu e un oracol, ci un ghicitor cu statistici; dacă tu îi dai date proaspete, ghicește bine. Următorul pas: ce faci când planul e bun, dar memoria e prea mică pentru el.
Deschide pe YouTube ↗ - 25
Lecția 25 · Într-un depozit columnar, structura de date e așezarea pe disc: partiția și ordinea decid câte blocuri nu trebuie citite.
Mesaj pe lista de discuții git · Linus Torvalds · 2006
Indexul B-tree e regele bazelor tranzacționale: găsește un rând în câțiva pași. Depozitele columnare merg pe alt principiu: nu caută un rând, sar peste blocuri. Fiecare bloc de coloană poartă un min și un max (zone map); dacă filtrul cere „luna martie” și blocul acoperă „iunie–iulie”, blocul nu se citește deloc. De aici două pârghii. Partiționarea — de regulă pe dată — elimină directoare întregi înainte să înceapă interogarea. Clusterizarea (sau cheia de sortare) grupează valorile apropiate în aceleași blocuri, ca zone map-urile să aibă ce sări; fără ea, fiecare bloc conține de toate și niciunul nu se poate sări. Regulile de proiectare urmează filtrele, nu sosirea datelor: partiționezi pe ce se filtrează în interogări, clusterizezi pe a doua coloană din WHERE. Prea multe partiții înseamnă fișiere mici și metadate mai scumpe decât datele; se compactează. Pentru egalitate pe coloane cu multe valori distincte, filtrele Bloom; pentru agregări repetate, vederi materializate; iar statisticile actualizate rămân condiția ca toate acestea să fie folosite. Torvalds vorbea despre cod, dar regula ține: nu optimiza interogarea; așază datele astfel încât interogarea să nu aibă ce citi.
Programatorii slabi se îngrijorează de cod. Programatorii buni se îngrijorează de structurile de date și de relațiile dintre ele.Mesaj pe lista de discuții git, 27 iunie 2006
De ce contează Diferența dintre o interogare de trei secunde și una de trei minute pe aceleași date e, de obicei, doar ordinea în care au fost scrise pe disc.
Pe larg →Strânge ↑
Pasajul de până acum explică cum partiția și sortarea taie blocuri. Pasul următor e mai puțin evident: aceste două pârghii se plătesc la scriere, nu doar la citire. Când alegi partiția și cheia de sortare, decizi de fapt ordinea în care datele intră pe disc, pentru totdeauna. O tabelă de comenzi partiționată pe lună și sortată după client va fi rapidă pentru rapoartele lunare pe client, dar lentă pentru orice filtru pe produs. De aceea proiectarea se face invers: te uiți întâi la întrebările care se vor pune, abia apoi la cum arată datele. Un exemplu obișnuit: arhivezi facturile lunare, dar contabilii filtrează mereu după furnizor. Dacă sortarea e pe dată, fiecare furnizor e risipit prin toate blocurile. Schimbi cheia de sortare și aceeași interogare citește o fracțiune. Dar ce se întâmplă când datele sosesc neordonate, în flux continuu, și nu le poți sorta odată?
În flux, datele sosesc în ordinea sosirii, nu în ordinea filtrului. Fiecare fișier mic primește un interval larg de valori, deci zone map-urile nu mai pot sări nimic. Soluția nu e să sortezi la citire, ci la scriere, mai târziu: compactarea. Sistemul unește fișierele mici în fișiere mari, sortate, și rescrie statisticile. E ca și cum ai arunca poșta în vraf toată ziua, apoi ai sorta-o seara în dosare. Interogările care rulează între timp plătesc prețul vrafului, dar cele de după citesc dosare. Apare însă o întrebare: cât de des să compactezi și cât de mari să fie fișierele?
Deschide pe YouTube ↗ - 26
Lecția 26 · Fiecare treaptă a memoriei e de o sută de ori mai lentă decât cea de deasupra; o interogare e rapidă exact cât rămâne pe treapta de sus.
Tape is Dead, Disk is Tape, Flash is Disk, RAM Locality is King · Jim Gray · 2006
Cifrele lui Gray sunt tot valabile ca ordine de mărime: RAM în nanosecunde, SSD în zeci de microsecunde, disc rotativ în milisecunde, stocare de obiecte în zeci de milisecunde plus un cost per cerere. Între trepte sunt factori de sută. „Discul e bandă” înseamnă că discul mai merită doar pentru citiri secvențiale — de aici formatul columnar, compresia și așezarea sortată din lecția 25: transformă accesul aleatoriu în parcurgere. „Localitatea în RAM e rege” înseamnă că interogarea rapidă e cea al cărei set de lucru încape în memorie: tabela hash a join-ului, sortarea, agregarea. În clipa în care nu mai încape, se varsă pe treapta următoare și încetinește de zece până la o sută de ori, fără să dea vreo eroare. Depozitele cloud fac ierarhia explicită: stocarea de obiecte e baza, ieftină și nelimitată; nodurile de calcul țin un cache pe SSD local; rezultatele recente stau într-un cache de rezultate. Dimensionarea nu e „câtă memorie are serverul”, ci „câtă memorie primește fiecare slot de interogare” — zece interogări paralele împart același RAM. Compresia columnară e, în termenii lui Gray, cel mai ieftin mod de a urca o treaptă: aceleași date, de cinci ori mai mici, încap acolo unde înainte nu încăpeau.
Banda e moartă, discul e bandă, flash-ul e disc, localitatea în RAM e rege.Prezentare la Storage Guru Gong Show, Redmond, 10 decembrie 2006 (reluată la CIDR 2007)
De ce contează O interogare care „a mers ieri” și azi durează de zece ori mai mult n-a devenit mai grea; setul ei de lucru a coborât o treaptă în ierarhie.
Pe larg →Strânge ↑
Partea tulburătoare a ierarhiei e că ea nu te avertizează. Când o interogare se varsă din memorie pe SSD, sistemul nu afișează nicio eroare; pur și simplu răspunde mai încet, de o sută de ori mai încet. Gândește-te la o cafea: dacă o lași zece minute, nu e stricată, doar rece. La fel, datele de pe treapta de jos nu sunt pierdute, doar departe. De aceea, diagnosticarea nu începe cu loguri, ci cu o întrebare simplă: ce cantitate de date a atins interogarea asta azi, față de ieri? Dacă răspunsul a trecut pragul memoriei, ai găsit cauza. Următorul pas e să vezi ce se poate face ca setul acela să încapă din nou sus.
Dacă setul de lucru nu încape, ai două pârghii: îl micșorezi sau îi dai mai mult loc. Compresia columnară e prima: aceleași date, de cinci ori mai mici, urcă o treaptă întreagă fără să le schimbi nimic. A doua e mai puțin evidentă: memoria unui server nu e a tuturor. Zece interogări paralele împart același RAM, deci fiecăreia îi revine o zecime. E ca o bibliotecă cu un singur birou: dacă vin zece cititori deodată, fiecare primește doar un colț de masă, iar restul cărților rămân pe raft. De aceea, dimensionarea nu întreabă câtă memorie are mașina, ci câtă primește fiecare interogare. Dar ce alegi întâi, când nu poți face niciuna din cele două?
Deschide pe YouTube ↗ - 27
Lecția 27 · La ce să fii atent: depozitele nu mor de tehnologie, mor de lipsa unui model, a unui proprietar și a unui utilizator.
The Mythical Man-Month · Frederick P. Brooks Jr. · 1975
Brooks spunea că tabelele explică sistemul; într-un depozit, tabelele sunt sistemul. Prima cauză de eșec e lipsa modelului: sursele copiate una lângă alta și numite „depozit”, fără fapte și dimensiuni, fără o definiție comună pentru „client” sau „venit” — deci trei rapoarte cu trei cifre. A doua e lipsa proprietarului: seturi fără cineva care răspunde de ele, fără teste, unde o coloană redenumită la sursă trece neobservată o lună. A treia e lipsa utilizatorului: un depozit construit „pentru când o să avem nevoie”, în loc de o decizie concretă de luni dimineață. Restul e o listă de verificat, pe scurt. Cheia surogat și cea naturală confundate, join-uri care multiplică rânduri. Fusuri orare și monede amestecate în aceeași coloană. Ora evenimentului confundată cu ora încărcării. NULL-ul care dispare din agregări și din join-uri fără să anunțe. Interogări nemărginite într-un sistem plătit pe citire. Date personale pe fiecare rând, fără seif și fără termen. Streaming acolo unde o încărcare zilnică era de ajuns. Și o documentație care lipsește — deși, cum spune Brooks, un tabel bine numit și bine cheiat e cea mai bună documentație pe care o vei scrie vreodată.
Arată-mi diagramele tale de flux și ascunde-ți tabelele, și voi rămâne nedumerit. Arată-mi tabelele, și de obicei nu voi mai avea nevoie de diagrame; vor fi evidente.The Mythical Man-Month (1975), cap. 9 — Ten Pounds in a Five-Pound Sack
De ce contează Nicio unealtă nu compensează un model lipsă, un set fără proprietar sau un depozit fără utilizator. Toate trei se văd în tabele, dacă te uiți.
Pe larg →Strânge ↑
Brooks a mutat atenția de la diagrame la tabele. Duci ideea cu un pas mai departe: un tabel poate fi citit ca un interogatoriu. Dacă numele coloanelor se contrazic între două tabele, modelul lipsește. Dacă nimeni nu poate spune cine a decis că prețul e fără TVA, proprietarul lipsește. Dacă nimeni nu rulează interogarea aceea de două ori, utilizatorul lipsește. Ia un exemplu obișnuit: facturile gospodăriei. Dacă tu și partenerul notați cheltuielile în același fișier, dar una scrie „mâncare” și celălalt „supermarket”, veți descoperi la final de lună că nu știți cât ați cheltuit de fapt. Fișierul există; modelul comun nu. Așa arată un depozit fără model, văzut din afară. Întrebarea practică devine: cine întreabă tabelul, și ce decide cu răspunsul?
Deschide pe YouTube ↗