„O facem direct în DAX, e mai rapid de scris.” Această frază, repetată într-o sută de echipe de BI, e cauza directă a celor mai multe modele Power BI lente și greu de întreținut.
Discuția Power Query vs DAX nu e una academică. E o decizie de arhitectură care, multiplicată pe zeci de calcule într-un model, separă raportul care se reîmprospătează în 30 de secunde de cel care durează 14 minute. Sau modelul care costă 600 EUR/lună în Premium capacity de cel care cere 2.000.
Power BI oferă două limbaje complet diferite pentru două scopuri complet diferite. Power Query (limbajul M) e pentru pregătirea datelor — transformarea brutului în ceva pe care modelul îl poate consuma eficient. DAX e pentru calculul măsurilor la momentul interogării — răspunsul la întrebarea pe care utilizatorul tocmai a pus-o printr-un filtru pe dashboard. Confuzia între cele două e cea mai costisitoare greșeală în Power BI.
Power Query DAX: Două limbaje, două momente diferite
Diferența fundamentală: Power Query rulează înainte de încărcarea datelor în model — la refresh. DAX rulează după încărcare — la fiecare interacțiune a utilizatorului cu raportul.
Asta înseamnă că tot ce faci în Power Query se „plătește” o singură dată per refresh (zilnic, orar, oricum ai configurat). Tot ce faci în DAX se plătește la fiecare click pe filtru, la fiecare swap între pagini, la fiecare expansiune de drill-down.
Implicația e brutală pentru performanță. O transformare costisitoare făcută în Power Query încetinește refresh-ul cu 10 minute o dată. Aceeași transformare făcută în DAX poate adăuga 3 secunde la fiecare interacțiune — care, înmulțite cu 200 de utilizatori care fac 50 de interacțiuni pe zi, devin 8 ore-CPU zilnice consumate degeaba.
Ce face fiecare cel mai bine
Power Query (M) — pregătirea datelor
Aici trebuie să trăiască:
- Curățare: trimming, casting, eliminare duplicate, gestionarea valorilor null
- Combinare surse: merge, append, lookup-uri între tabele eterogene
- Calcularea coloanelor care nu depind de context: coloane derivate static (an extras din dată, categoria din SKU, regiunea din cod)
- Filtrarea timpurie: dacă raportul are nevoie doar de ultimele 24 de luni, nu încărca 10 ani
- Reshape-ul: pivot, unpivot, transpose
- Tipizare: conversia coloanelor la tipurile corecte (numeric, dată, text)
Toate astea se fac cel mai bine în Power Query — pentru că rezultatul lor e o tabelă curată, pregătită, pe care motorul VertiPaq o poate comprima eficient.
DAX — măsuri dinamice și context filtrelor
Aici trebuie să trăiască:
- Măsurile agregate care reacționează la filtrele utilizatorului (vânzări totale, medie, count distinct)
- Calcule de time intelligence (year-over-year, year-to-date, moving averages)
- Ratios și KPI-uri compuse (marja %, conversion rate, market share)
- Calcule care depind de selecția din slicer-e (top N, ranking dinamic, what-if scenarios)
- Funcții care folosesc CALCULATE pentru a manipula context-ul de filtru
Toate astea trebuie să fie dinamice — depind de ce alege utilizatorul. Așa că nu pot fi pre-calculate în Power Query. DAX e instrumentul corect.
Capcana coloanelor calculate
Coloanele calculate în DAX sunt zona cea mai des încurcată. Sintactic seamănă cu măsurile (scrii formulă DAX), dar comportamental sunt diferite: se evaluează o dată la refresh, ca rezultatele Power Query, și se stochează în model.
Întrebarea logică devine: dacă o coloană calculată DAX se evaluează la refresh, de ce să nu fie făcută în Power Query?
Răspunsul: aproape întotdeauna ar trebui să fie. Excepția — situațiile în care ai nevoie de context evaluation funcție de relațiile din modelul Power BI (RELATED, RELATEDTABLE), pe care Power Query nu îl poate accesa.
În rest, o coloană calculată în Power Query e mai eficient stocată, mai bine comprimată de VertiPaq, mai ușor de propagat ca lineage către surse. O coloană calculată în DAX e plătită din motorul de calcul al modelului, blochează unele optimizări și e mai greu de auditat.
Regula simplificată: dacă poți face transformarea în M, fă-o în M. Folosește coloane calculate DAX doar când chiar ai nevoie de relații RELATED.
Costul real în practică
Un exemplu din viața reală, dintr-o echipă de BI la o companie românească de retail cu 32 de magazine. Modelul: 18 milioane de rânduri în tabela de tranzacții, 40.000 de produse, 32 de magazine, 4 ani de istoric.
Versiunea inițială avea 14 coloane calculate DAX în tabela de fact: an, lună, săptămână, trimestru, categorie produs, sub-categorie, regiune magazin, ranking-uri lunare, etc. Plus 47 de măsuri DAX, dintre care 12 făceau calcule peste aceste coloane calculate.
- Dimensiune model: 980 MB
- Refresh time: 47 de minute
- Timp mediu de răspuns la slicer: 4-7 secunde
După refactorizare — mutarea celor 14 coloane calculate în Power Query, plus normalizarea în dimension tables a celor care nu erau static derivate:
- Dimensiune model: 340 MB
- Refresh time: 22 de minute
- Timp mediu de răspuns la slicer: 0,8-1,5 secunde
Reducere de aproape 65% pe dimensiune. Refresh-ul s-a tăiat la jumătate. Interacțiunile se simt aproape instant.
Costul refactorizării: aproximativ 12 ore-om de senior BI. Câștigul anual estimat: 4-5x în experiență utilizator + posibilitatea de a rămâne pe Pro în loc să forțeze upgrade la Premium.
Reguli de decizie rapide
Pentru cineva care construiește un model nou sau care evaluează unul existent, câteva întrebări care taie zgomotul.
Coloana se evaluează static, pe baza altor coloane din același rând? → Power Query.
Coloana are nevoie de RELATED pentru a accesa o relație? → DAX coloană calculată (excepția).
Valoarea trebuie să se schimbe în funcție de ce filtrează utilizatorul? → Măsură DAX.
Faci un calcul de time intelligence (YoY, YTD, MoM)? → Măsură DAX cu funcțiile dedicate.
Vrei să faci pivot, unpivot, merge cu altă sursă? → Power Query.
Trebuie să filtrezi sursa înainte să încarci ca să nu aduci 80% date inutile? → Power Query.
Există însă o capcană aici
Power Query nu e mereu rapid. Pe surse mari (data warehouse-uri cu zeci de milioane de rânduri), refresh-ul prin Power Query poate fi mult mai lent decât o procedură stocată sau o view materializată pe sursă.
Regula empirică: dacă o transformare poate fi făcută pe sursă (în SQL, în Fabric Dataflow Gen2, într-un ETL extern), aproape întotdeauna acolo aparține. Power Query e ideal pentru surse mid-volume sau pentru ajustări finale care nu pot fi făcute pe sursă.
În echipele mature, Power Query face din ce în ce mai puțin. Curățarea grea se mută în dataflows sau direct în warehouse. Modelul Power BI primește date deja pregătite. Asta lasă DAX-ului spațiul să facă ce face mai bine — măsuri dinamice rapide.
Cazul Fabric și al lakehouse-urilor
Cu Microsoft Fabric matur la sfârșitul lui 2026, granița între „transformare în Power Query” și „transformare upstream” se mută vizibil. Lakehouse-urile permit modelarea în Spark sau SQL direct pe layer-ul de date, cu Power BI conectat în DirectLake mode.
În acest model, Power Query se simplifică drastic — sau dispare cu totul pentru modele complexe. DAX rămâne, dar și el evoluează: măsurile complexe se mută în calculation groups bine structurate, iar logica grea se duce în notebook-urile din lakehouse.
Pentru un data analyst care învață acum, vestea bună e că disciplina rămâne aceeași: transformările statice merg upstream (acum în lakehouse, înainte în Power Query); calculele dinamice rămân în DAX. Doar locația „upstream-ului” se schimbă.
Greșeli frecvente care costă bani
Pe baza a sute de modele auditate în piața românească, câteva pattern-uri se repetă obsesiv.
Coloane care extrag „An”, „Lună”, „Trimestru” din coloana de dată — făcute în DAX cu YEAR(), MONTH(), QUARTER(). Soluția corectă: tabela de calendar dedicată, generată o singură dată în Power Query, cu toate aceste coloane pre-calculate și conectate prin relație.
Coloane care calculează „categoria de venit” (mic/mediu/mare) pe baza unei coloane numerice — făcute în DAX cu SWITCH/IF. Soluția: în Power Query, conditional column, care produce o coloană categorică compresată eficient de VertiPaq.
Filtre aplicate în DAX cu CALCULATE pe coloane care ar putea fi pre-filtrate în Power Query — încarcă date inutile în model, încetinesc totul.
Coloane calculate care fac LOOKUPVALUE pe altă tabelă — în 95% din cazuri, asta înseamnă că modelul de date nu are relații corecte. Soluție: refă relațiile, scapă de LOOKUPVALUE.
Trei scenarii frecvente și răspunsul corect
Scenariul A: extragerea anului și a lunii dintr-o coloană de dată
O echipă care construiește primul model adaugă în mod natural coloane „Year” și „Month” cu formule DAX simple — YEAR([OrderDate]) și MONTH([OrderDate]). Pare logic. Și e greșit.
Soluția corectă: construiește o tabelă de calendar dedicată în Power Query, generată cu funcția List.Dates sau cu o sursă externă. Conectează-o prin relație la tabela de fact. Vei avea automat: An, Trimestru, Luna, Săptămâna, Ziua săptămânii, Flag-uri pentru weekend/holiday, etichete formatate pentru limbi diferite. Toate compresate eficient de VertiPaq, toate reutilizabile în orice raport viitor.
Scenariul B: clasificare clienți pe categorii de venit
Echipa vrea să grupeze clienții în „mici” (sub 10K), „medii” (10-100K), „mari” (peste 100K) pe baza venitului total. Implementarea naivă: o coloană calculată DAX cu SWITCH.
Soluția corectă: depinde. Dacă valoarea totală a clientului e stabilă (calculat lunar/trimestrial, nu live), categoria merge în Power Query — calculată din suma istoricului. Dacă vrei ca segmentarea să se actualizeze dinamic în funcție de perioada selectată în slicer, atunci da, DAX cu măsură. Dar nu cu coloană calculată — cu măsură care folosește SELECTEDVALUE + CALCULATE.
Scenariul C: calcularea marjei procentuale
Cu siguranță în DAX, cu siguranță ca măsură. Aceasta e exact tipul de calcul care e dinamic: depinde de filtrele aplicate, trebuie să recalculeze la fiecare interacțiune. DIVIDE(SUM('Sales'[Margin]), SUM('Sales'[Revenue])) e răspunsul corect.
Greșeala frecventă: calcularea marjei la nivel de rând (în Power Query sau ca coloană calculată) și apoi încercarea de a face media pe ea. Asta dă rezultate greșite — marja agregată nu e media marjelor individuale, e raportul totalurilor.
Cum auditezi un model existent
Pentru cine moștenește un model Power BI și vrea să identifice rapid problemele, câteva tool-uri esențiale.
DAX Studio — gratuit, indispensabil. Permite analiză detaliată a fiecărei măsuri, identificarea celor lente, evaluarea storage engine vs. formula engine. O sesiune de 2-3 ore cu DAX Studio pe un model nou descoperă majoritatea problemelor de performanță.
VertiPaq Analyzer — integrat în DAX Studio. Arată cât spațiu ocupă fiecare coloană în model. Coloanele cu cardinalitate mare și compresie slabă sunt candidatele perfecte pentru optimizare — fie eliminate, fie reformulate în Power Query pentru a reduce cardinalitatea.
Tabular Editor — versiune gratuită (2.x) sau Pro (3.x). Permite manipularea structurală a modelului mult mai eficient decât interface-ul nativ Power BI. Esențial pentru calculation groups.
Un audit complet pe un model mid-size durează 4-8 ore. Rezultatul tipic: lista cu 10-15 optimizări concrete, ordonate după impact. Implementarea: 2-3 zile de muncă, returnul: 40-70% reducere în timp de refresh, modele mai mici, costuri de licență mai mici.
Tema se leagă natural de discuția despre Power BI vs Tableau, unde am intrat în detaliu pe pattern-urile pe care le observăm în piață. Pentru actualizări și detalii suplimentare, Power BI Blog rămâne sursa principală pe acest subiect. În fond, Power Query DAX nu e doar un concept tehnic — este o decizie de business cu impact direct pe productivitatea echipei.
Recomandare concretă
Pentru cine începe acum sau revizuiește un model existent, ordinea pragmatică e simplă:
Întâi, mută toate coloanele calculate DAX care nu folosesc RELATED în Power Query. Vei vedea probabil o reducere de 30-50% a dimensiunii modelului.
Apoi, identifică top 5 măsuri DAX cele mai folosite în rapoarte și analizează-le cu DAX Studio (gratuit, dezvoltat de SQLBI). Vei descoperi probabil 2-3 oportunități de simplificare.
În final, evaluează ce transformări din Power Query ar putea merge mai sus — într-un dataflow, într-o view SQL, într-un lakehouse table. Asta mai reduce încă 20-30% timpul de refresh.
Investiția: 1-2 zile per model. Returnul: rapoarte mai rapide, costuri de licență mai mici, mai puține plângeri de la utilizatori. Pe modele mari în companii cu 100+ utilizatori, ROI-ul se vede în prima săptămână.
Și nu, „o facem direct în DAX, e mai rapid de scris” rămâne o glumă scumpă. Diferența între un raport bine arhitecturat și unul prost arhitecturat se vede direct pe factura lunară de Power BI și pe răbdarea managerilor.
În practică, Power Query DAX a trecut de la subiect de roadmap la prioritate operațională pentru echipele care livrează rezultate de business — exact tipul de tracțiune pe care o vedem reflectată în deciziile reale de buget. Pentru cititorii care lucrează zilnic cu Power Query DAX, articolul rămâne deschis pentru update-uri pe măsură ce piața evoluează.
Întrebări frecvente
Care e diferența de fond între Power Query și DAX?
Momentul în care rulează. Power Query rulează înainte de încărcarea datelor în model, la refresh, deci tot ce faci acolo se plătește o singură dată per refresh. DAX rulează la interogare, de fiecare dată când cineva atinge un filtru. Implicația pentru performanță e brutală.
Ce fac în Power Query?
Pregătirea datelor: curățare — trimming, casting, eliminarea duplicatelor, tratarea valorilor null; combinarea surselor prin merge, append și lookup-uri; coloanele derivate static, care nu depind de context, cum ar fi anul extras din dată sau categoria din SKU; filtrarea timpurie, ca să nu încarci 10 ani dacă raportul are nevoie de 24 de luni; pivot, unpivot și transpose; și tipizarea coloanelor.
Ce las în DAX?
Măsurile care reacționează la filtrele utilizatorului — total, medie, count distinct; calculele de time intelligence, precum year-over-year, year-to-date și medii mobile; rapoartele și KPI-urile compuse, ca marja procentuală sau rata de conversie; și calculele care depind de selecția din slicere, cum sunt top N, ranking dinamic și scenariile what-if.

