DP-600 · Kapitola 7
Semantic modely, DAX a optimalizace
Storage mody, Direct Lake, mental model DAXu, RLS / OLS a toolset pro výkon
Cíle kapitoly
- Vybrat storage mode semantic modelu (Import, DirectQuery, Direct Lake) podle dat a požadavků
- Vysvětlit row context, filter context a CALCULATE na příkladech nad daty ČHMÚ
- Rozumět framingu a fallbacku Direct Lake a jeho limitům
- Projít optimalizační workflow s Performance Analyzerem, DAX Studiem a VertiPaq Analyzerem
- Nastavit RLS / OLS a chápat propagaci sensitivity labelů
7.1
Úvod
Poznámky a demo runbook pro Day 3. Audience má SQL/PBI background — DAX intro lze zkrátit, optimalizace deep-dive.
Demo data: gold layer z Days 1-2 —
gold_fact_kvalita_ovzdusi + dim_station, dim_kraj, dim_pollutant, dim_date. Žádný nový dataset, žádný nový workspace.7.2
Semantic Model architektura — kdy co
SCHÉMA
┌─────────────────────────────────────────────────────────────┐ │ STORAGE MODE per table v semantic modelu │ │ │ │ Import DirectQuery Direct Lake │ │ ────────── ───────────── ─────────────── │ │ • Data v PBI • Query → source • OneLake Delta │ │ cache (.pbix) each interaction no-copy reference │ │ • Refresh = • Live but slow • Framing každých ~10min │ │ full reload • Cap 1M rows/visual • Sub-sec performance │ │ • Best perf • RLS pass-through • F-SKU only │ │ • Cap dataset • Fallback to DQ on miss │ │ size (10GB Použít: real-time Použít: large fact + │ │ Premium) malé dotazy PBI experience │ └─────────────────────────────────────────────────────────────┘
Decision tree
SCHÉMA
Data velikost > 10GB?
├── ANO → Direct Lake (default pro Fabric semantic modely)
└── NE
│
Real-time refresh required (sub-min)?
├── ANO → DirectQuery (na DW/SQL DB) nebo Direct Lake nad streamem
└── NE → Import (best performance)Composite model (Day 4 RTI integration)
PBI semantic model může mít mix storage modes per table:
dim_station→ Direct Lake (Lakehouse)gold_fact_kvalita_ovzdusi→ Direct Lake (Lakehouse, batch historic)mv_b_chmi_last_per_station→ DirectQuery (KQL DB, real-time current state)
Měřítka mohou kombinovat sloupce z různých storage modes — RELATED přes vztahy. Limit: cross-storage joins jsou drahé, vyhni se velkým fact-fact joins napříč storage modes.
7.3
DAX — co audience musí pochopit
Mental model: 2 contexts
DAX má dvě "okna" do dat:
- Row context — kde právě jsem v tabulce (jeden řádek)
- Filter context — co je filtrováno na visual / report
DAX
-- Row context: SUMX iteruje řádky Total Revenue = SUMX(Sales, Sales[Quantity] * Sales[UnitPrice]) -- Filter context: SUM bere agregát Total Revenue Simple = SUM(Sales[Total])
Klíčový insight: SQL nemá row context out-of-the-box, jen aggregations + WINDOW functions. DAX iterators (
SUMX, AVERAGEX, MAXX, ...) jsou ekvivalent SQL window functions, ale s implicit row context.CALCULATE = 50% DAX power
DAX
-- Modify filter context Revenue YTD = CALCULATE([Total Revenue], DATESYTD('Date'[Date])) -- Remove filter (ALL) Revenue All Time = CALCULATE([Total Revenue], ALL('Date')) -- Replace filter Revenue Praha = CALCULATE([Total Revenue], 'dim_station'[kraj_kod] = "PHA") -- Combine Revenue YTD vs LY = VAR ytd = CALCULATE([Total Revenue], DATESYTD('Date'[Date])) VAR ly = CALCULATE([Total Revenue], DATESYTD(SAMEPERIODLASTYEAR('Date'[Date]))) RETURN ytd - ly
Time intelligence — must-know pattern
DAX
PM10 Avg Today = AVERAGE(gold_fact_kvalita_ovzdusi[pm10]) PM10 Avg YTD = CALCULATE([PM10 Avg Today], DATESYTD('Date'[Date])) PM10 Avg Same Period Last Year = CALCULATE([PM10 Avg Today], SAMEPERIODLASTYEAR('Date'[Date])) PM10 YoY % = DIVIDE( [PM10 Avg YTD] - [PM10 Avg Same Period Last Year], [PM10 Avg Same Period Last Year] )
CALCULATE filter context modifier reference (top 10)
| Modifier | Co dělá | SQL ekvivalent |
|---|---|---|
ALL(table) |
Remove all filters from table | OVER() |
ALL(col) |
Remove filter from one column | OVER (PARTITION BY ...) excluding col |
ALLEXCEPT(table, col1, col2) |
Remove all filters except listed | – |
KEEPFILTERS(filter) |
Add to existing filter, don't override | – |
REMOVEFILTERS(table/col) |
Same as ALL but more explicit (DAX 2019+) | – |
USERELATIONSHIP(col1, col2) |
Activate inactive relationship | – |
CROSSFILTER(col1, col2, dir) |
Override cross-filter direction | – |
FILTER(table, predicate) |
Row-by-row filter (slow on large tables) | WHERE |
TREATAS({values}, col) |
Apply virtual filter from values | IN (...) |
SELECTEDVALUE(col) |
Get single value if filter has 1 row | – |
7.4
Demo runbook (live)
Setup (před lekcí)
- Workspace
DP600_Demo_CHMIs gold layerem z Days 1-2 - PBI Desktop nebo Power BI Service workspace
- New semantic model: Direct Lake nad gold tables
Demo 1: Build semantic model
- Lakehouse → New semantic model → vyber
gold_fact_kvalita_ovzdusi,dim_station,dim_kraj,dim_pollutant,dim_date - Otevři Model view — auto-detect relationships (zkontroluj že FKs sedí)
- Hide ID columns, mark
dim_date[date]as date table - Live demo: refresh = framing (rychlé)
Demo 2: 3 measures progresivně
DAX
-- Lekce: aggregate, no context manipulation Avg PM10 = AVERAGE(gold_fact_kvalita_ovzdusi[pm10]) -- Lekce: time intelligence Avg PM10 YTD = CALCULATE([Avg PM10], DATESYTD('dim_date'[date])) -- Lekce: ranking + topN Top 5 Stations PM10 = RANKX( ALL('dim_station'[station_nazev]), [Avg PM10], ,DESC,Dense )
Postaveno na obrazovce — matrix dim_kraj × dim_pollutant na value [Avg PM10], pak přidat [Avg PM10 YTD], pak slicer dim_date.
Demo 3: RLS
- Modeling → Manage roles → New:
Kraj_Filter - Table
dim_station→ DAX rule:
DAX
[kraj_kod] = LOOKUPVALUE( 'dim_user'[kraj_kod], 'dim_user'[email], USERPRINCIPALNAME() )
- Test as role — vidíš jen jeden kraj
- Publish → assign role v Power BI Service
Demo 4: Performance Analyzer + DAX Studio
- PBI Desktop → View → Performance Analyzer → Start
- Refresh visual, zkopíruj query
- Otevři DAX Studio, paste query
- Run with Server Timings — vidíš FE vs SE split, Storage Engine query plan
- Iterate: optimize measure, re-measure
7.5
Direct Lake deep-dive
Co to je
- Semantic model nereaduje data do paměti při refreshu
- Místo toho referencuje Delta soubory v OneLake přímo
- Při query: VertiPaq engine on-demand loaduje column dat z Delta
Framing
- Power BI průběžně sleduje Delta
_delta_log; při detekci nové verze proběhne framing (automatické aktualizace lze vypnout a řídit refresh ručně) - Pokud nová verze: framing (lightweight metadata reload, ne data reload)
- User vidí fresh data bez explicit refresh button
Fallback to DirectQuery
- Týká se Direct Lake on SQL endpoint: model spadne do DirectQuery přes SQL analytics endpoint, když překročí guardrail kapacity (počet řádků, velikost modelu), když tabulka stojí na SQL view, nebo když endpoint vynucuje RLS/OLS. „Studené“ sloupce se jen dočtou do paměti — fallback nezpůsobí
- Indikováno warning v Performance Analyzer:
Storage Mode = DirectQuery - Hot point pro audience: monitorovat fallback (Performance Analyzer, DAX Studio) — je to signál překročeného guardrailu nebo view v modelu. Direct Lake on OneLake (novější varianta) do DirectQuery nepadá vůbec a umí i tabulky z více zdrojů; volba mezi oběma variantami je explicitní cíl zkoušky
Limitace Direct Lake
- F-SKU only (ne Pro/PPU)
- Guardraily per kapacita — řádků na tabulku: F2–F32 300 M, F64 1,5 mld., F128 3 mld.; velikost modelu F2–F8 10 GB, F16 20 GB, F32 40 GB (přesné hodnoty ověřte v dokumentaci)
- Některé DAX funkce nejsou supported (USERELATIONSHIP s caveats, COLUMNSTATISTICS, ...)
- Calculated columns / tables: na Direct Lake on SQL endpoint nejsou podporované (počítejte je v Lakehouse jako materializované sloupce); Direct Lake on OneLake je má v preview — ověřte aktuální stav
Cost
- Direct Lake = single capacity unit pricing (na rozdíl od Pro $14/user, od dubna 2025)
- Pro 8 účastníků s F2 capacity: ~$200/měsíc, sdílené
- Vs Premium per user (PPU): 8 × $24 = $192/měsíc, ale bez Lakehouse, bez Spark
7.6
Performance & optimization workflow
Step 1: Identifikuj slow visual
- PBI Desktop → View → Performance Analyzer → Start recording
- Interaguj s reportem (filtry, slicery)
- Stop → tabulka per-visual: DAX query time + Visual display time
Step 2: Analyze query
- Click "Copy query" na slow visual
- Otevři DAX Studio (free, https://daxstudio.org/)
- Connect k tvému PBI model (Desktop nebo Service)
- Paste query → enable Server Timings → Run
- View pane: Storage Engine queries + Formula Engine time breakdown
Step 3: Optimize
Common patterns:
- Replace iterators s vector ops kde možné (
SUMX(table, [col])→SUM(table[col])) - Reduce row context transitions — vyhni se
[measure]vFILTERpredikátu - Use variables (
VAR x = ...) pro reuse výpočtu - CALCULATE filter lépe než
FILTER(ALL(...), ...)pro simple equality
Step 4: VertiPaq Analyzer (storage optimization)
- DAX Studio → VertiPaq Analyzer view
- Per-table per-column metrics: cardinality, dictionary size, columns size
- Top offenders typically:
- High cardinality columns (timestamps with seconds → bin to minute)
- Free-text columns (PII, descriptions → hash or remove)
- Calculated columns (compute v Lakehouse místo v PBI)
Step 5: Tabular Editor 2 (free)
- Bulk edit measures, perspectives, calc groups
- Best Practice Analyzer (BPA) — automatic anti-pattern detection
- Edit RLS roles bulk
Doporučený toolset (handout)
| Tool | Cena | Co dělá | Kdy použít |
|---|---|---|---|
| Performance Analyzer (built-in) | free | Identifikuj slow visual | první krok vždy |
| DAX Studio | free | Profiling, Server Timings | každý slow query |
| VertiPaq Analyzer | free (in DAX Studio) | Storage analysis | optimalizace size |
| Tabular Editor 2 | free | Bulk edit | každý větší model |
| Tabular Editor 3 | $200/year | TE2 + advanced (script library, BPA, deployments) | enterprise |
| ALM Toolkit | free | Schema diff + deploy | CI/CD scénáře |
| BI Helper | free | Documentation gen | dokumentace modelů |
7.7
RLS / OLS / Sensitivity labels
RLS (Row-Level Security)
- DAX expression na tabulce, vyhodnocuje se pre-query
- 2 modes: Static (filter literal value) nebo Dynamic (
USERPRINCIPALNAME()based) - Test v PBI Desktop: Modeling → View as → Other user
DAX
-- Static [kraj_kod] = "PHA" -- Dynamic via dimension table [kraj_kod] IN SELECTCOLUMNS( FILTER('dim_user', 'dim_user'[email] = USERPRINCIPALNAME()), 'dim_user'[kraj_kod] )
OLS (Object-Level Security)
- Hide tables/columns based on role
- Configured via Tabular Editor (PBI UI does not have native UI yet)
- Model definition (TMSL/TMDL):
TMDL
table dim_salary tablePermissions Manager: ReadAll, Worker: None
Sensitivity Labels (MIP)
- Microsoft Information Protection labels propagated z OneLake
- Auto-applied na PBI semantic model na základě upstream Lakehouse
- Lze override v PBI ručně (audit log records change)
- Downstream: PBI report inheritne label, export má watermark
3-layer security mental model
SCHÉMA
Layer 1: Workspace role (Admin/Member/Contributor/Viewer)
└── kdo vidí workspace a co může v něm dělat
Layer 2: Item permission (semantic model Read/Build)
└── kdo může konzumovat / build na top
Layer 3: RLS / OLS / Labels
└── jaká data konkrétní user vidí7.8
Day 3 hands-on labs (konsolidovaný blok)
Doporučené laby z MS Learn (vybrat 1-2):
| Lab | Učební cíl |
|---|---|
| Lab 5: Build semantic model from Lakehouse | Direct Lake basics |
| Lab 6: Write DAX measures | CALCULATE + time intelligence |
| Lab 7: Implement RLS | Dynamic RLS s user mapping |
| Lab 8: Optimize semantic model | DAX Studio + VertiPaq |
Pokud má tým SQL background a žádný DAX → preferuj Lab 6. Pokud audience má PBI experience → preferuj Lab 8 (advanced).
7.9
Day 3 troubleshooting
| Problem | Fix |
|---|---|
| Direct Lake fallback to DQ | Performance Analyzer → check warning. Příčina: překročený guardrail (řádky / velikost modelu), view místo tabulky, nebo RLS na SQL endpointu. Fix: zmenšit model / zvednout F-SKU / přejít na Direct Lake on OneLake. |
| RLS test "View as role" prázdná tabulka | DAX expression vrací FALSE pro user. Check USERPRINCIPALNAME() mapping table. |
| Time intelligence neproveze | dim_date musí být marked as date table, contigous range, no gaps. |
CALCULATE warning "Filter argument modifies columns from multiple tables" |
Use KEEPFILTERS nebo split CALCULATE do více volání. |
| Slow visual po publish ale rychlý v Desktop | Capacity throttling. Capacity Metrics App → Throttling tab. |
7.10
Reference
- DAX guide (oficiální): dax.guide
- DAX patterns (Marco Russo): https://www.daxpatterns.com/
- Direct Lake docs: https://learn.microsoft.com/fabric/get-started/direct-lake-overview
- Performance Analyzer: https://learn.microsoft.com/power-bi/create-reports/desktop-performance-analyzer
- DAX Studio: https://daxstudio.org/
- Tabular Editor: https://tabulareditor.com/
- VertiPaq Analyzer: vestavěný v DAX Studio
- RLS docs: https://learn.microsoft.com/power-bi/admin/service-admin-rls