Twee seconden in Desktop, twintig in de Service: de composite model-valkuil
Een patroon blijft opduiken in Fabric-communitythreads: een rapport laadt in zo'n twee seconden in Power BI Desktop, maar duurt tien tot twintig keer langer nadat het gepubliceerd is in de Service. Het model ziet er redelijk uit: een DirectQuery-verbinding met een Tabular semantic model, een handvol geïmporteerde SharePoint-lijsten als referentiedata en relaties die ze aan elkaar koppelen. Niets bijzonders.
De aanname is dat geïmporteerde tabellen sneller zijn dan DirectQuery-tabellen, dus dat het mixen ervan zou helpen. Dat doet het niet. Desktop maskeert het probleem omdat het draait op een lokale Analysis Services-instantie met minimale netwerklatentie. De Service voegt round-trip overhead toe tussen de front-end, de AS-engine en de externe DirectQuery-bron. Elke cross-source join vergroot die overhead.
Het echte probleem is architecturaal. Een composite model met zowel DirectQuery als Import-tabellen dwingt de formula engine om als orchestrator te fungeren tussen twee storage engines. Het kan geen enkele native query naar de bron sturen. In plaats daarvan stuurt het afzonderlijke queries naar elke engine, haalt gedeeltelijke resultaten op in het geheugen en rijgt ze aan elkaar. Deze serialisatie vernietigt het parallellisme dat elke modus afzonderlijk snel maakt.
Microsoft's eigen documentatie is duidelijk: composite models die Import-tabellen combineren met DirectQuery-tabellen hebben implicaties die niet aanwezig zijn in single-mode models. De documentatie stopt net voor het woord 'trager', maar de query plans liegen niet. Wanneer je een DAX-measure ziet die CALCULATE uitvoert met REMOVEFILTERS over een geïmporteerde dimensie terwijl de fact table in DirectQuery staat, zie je de formula engine handmatig werk doen dat de storage engine zou moeten afhandelen.
SWITCH-intensieve measures veroorzaken opeenvolgende cross-source queries
Het specifieke DAX-patroon dat dit probleem het genadeloos blootlegt, is een P&L-measure die SWITCH gebruikt over rijindexbereiken. Een typische implementatie controleert of de huidige rij een detailregel of een subtotaal is en vertakt vervolgens naar verschillende CALCULATE-expressies, waarbij elke expressie REMOVEFILTERS toepast op een indexkolom en filtert op een ander numeriek bereik.
In een puur Import-model is dit patroon te verdragen. De storage engine lost elke vertakking op tegen de VertiPaq-kolomopslag in microseconden. In een composite model genereert elke CALCULATE-vertakking die een DirectQuery-fact table raakt een aparte native query. Een SWITCH-statement met zes vertakkingen kan zes round-trips naar de externe bron produceren, waarbij elke trip wacht tot de vorige klaar is als ze afhankelijkheden in de filtercontext delen.
De communitydiscussie die aanleiding gaf tot dit artikel liet precies dit zien: een measure die Brutowinst, Totale Overhead, Personeelskosten, EBITDA en EBIT berekent als afzonderlijke SWITCH-vertakkingen, elk met CALCULATE en verschillende REMOVEFILTERS-operaties. In Desktop verwerkte de lokale AS-engine dit in minder dan twee seconden. In de Service triggerde elke vertakking een externe query en de cumulatieve latentie maakte het rapport onbruikbaar.
Twee specifieke DAX-antipatronen maken dit erger. Ten eerste: het gebruik van bereikpredicaten zoals [Index] > 7 && [Index] < 10 in plaats van expliciete waardenlijsten met de IN-operator. Bereikpredicaten verhinderen dat de storage engine hash-lookups kan gebruiken. Ten tweede: afhankelijkheid van beperkte relaties tussen geïmporteerde en DirectQuery-tabellen dwingt de formula engine TREATAS of interne crossjoins te gebruiken in plaats van native joins, wat een extra serialisatiestap toevoegt.
Het vervangen van bereikcondities door [Index] IN {8, 9} stelt de engine in staat een efficiëntere WHERE-clausule te genereren. Een kleine wijziging met meetbaar effect: doorgaans 15-30% minder querytijd per vertakking in DirectQuery-modus.
Het formula engine-knelpunt: waarom consolidatie beter werkt dan optimalisatie
Om te begrijpen waarom consolidatie beter presteert dan DAX-optimalisatie, moet je weten hoe de twee Analysis Services-engines werk verdelen. De storage engine (SE) haalt data op uit VertiPaq (Import) of de externe bron (DirectQuery). De formula engine (FE) evalueert DAX-logica: iteratorfuncties, contextovergangen en SWITCH-vertakkingen. In een single-mode model doet de SE het meeste zware werk. In een composite model neemt de FE orchestratietaken op zich waarvoor hij nooit ontworpen is.
Wanneer de FE een measure tegenkomt die verwijst naar kolommen uit zowel een Import-tabel als een DirectQuery-tabel, kan hij de volledige berekening niet delegeren aan één SE. Hij moet elke SE onafhankelijk bevragen, tussenliggende resultaten in het geheugen materialiseren (een datacache) en vervolgens de resterende DAX-logica toepassen. Deze datacaches zijn de verborgen kosten van composite models. Ze verbruiken geheugen op de capacity, serialiseren query-uitvoering en profiteren niet van VertiPaq-compressie of DirectQuery-pushdown.
Daarom is de meest effectieve oplossing vrijwel altijd consolidatie in plaats van DAX-herschrijving. De SharePoint-lijstdata verplaatsen naar het basismodel (door ze daar te importeren of te repliceren naar dezelfde SQL/Dataverse-bron) elimineert de cross-source grens volledig. Elke query kan worden opgelost door één SE en de FE keert terug naar zijn bedoelde rol: expressies evalueren in plaats van dataverplaatsing orkestreren.
Als consolidatie niet mogelijk is (vanwege rechten, vereisten voor dataverversing of organisatorische grenzen), is de beste vervolgstap het herstructureren van relaties. Het gebruik van TREATAS met CALCULATETABLE om filtercontext handmatig van geïmporteerde dimensies naar DirectQuery-feiten te duwen, vermijdt de 'limited relationship'-straf. Het is uitgebreidere DAX, maar het geeft je expliciete controle over welke waarden de brongrens oversteken.
Performance Analyzer onthult de verdeling, als je weet waar je moet kijken
Power BI Desktop's Performance Analyzer (Beeld > Performance Analyzer) is het eerste gereedschap om naar te grijpen, maar de output is misleidend in composite models als je alleen de bovenste tijdsduur leest. De totale tijd die voor een visual wordt gemeld, omvat zowel de DirectQuery-duur als de stitching-overhead van de formula engine, maar maakt ze niet duidelijk onderscheidbaar.
Om de cross-source-kosten te isoleren, start je een Performance Analyzer-opname, interacteer je met het rapport en vouw je de trace van elke visual uit. Zoek naar het 'Direct Query'-item onder elke visual: dat toont de wachttijd voor de externe bron. Trek dit af van de totale visuele duur. De rest is formula engine-overhead: contextovergangen, datacache-materialisatie en cross-source joins. In een goed geöptimaliseerd single-mode model zou dit restant onder de 100 ms moeten zijn. In een composite model met SWITCH-intensieve measures overschrijdt het regelmatig de DirectQuery-tijd zelf.
Voor diepere analyse: verbind DAX Studio met de gepubliceerde dataset (als je capacity en rechten dit toelaten). Voer Server Timings uit op de problematische measure. Het tabblad SE queries toont afzonderlijke items voor VertiPaq en DirectQuery-aanroepen. Tel ze. Als een enkele measure meer dan drie SE-queries genereert, zijn SWITCH-vertakkingen of cross-source joins waarschijnlijk de oorzaak.
DAX Studio onthult ook een andere composite model-straf: query fusion failures. In puur Import-modus kan de SE meerdere VertiPaq-scans samenvoegen tot één batch. In composite-modus kunnen scans op verschillende engines niet worden samengevoegd. Elke scan blijft onafhankelijk en de FE verwerkt ze sequentieel. Dit is het mechanisme achter de 'het was snel, nu is het traag'-ervaring die volgt op het omzetten van een model van Import naar Composite.
Leg de Server Timings-output vast vóór en na het consolideren van tabellen. De vermindering van het aantal SE-queries is het duidelijkste bewijs dat de oplossing heeft gewerkt.
Bescherming voor composite models die composite moeten blijven
Soms is consolidatie niet mogelijk. De DirectQuery-bron is een gepubliceerd Tabular model van een ander team. De SharePoint-lijsten worden real-time bijgewerkt en de business vereist verversing met een interval van minder dan een uur. De organisatorische grens is reële. In deze gevallen kunnen defensieve DAX en modelontwerp de schade beperken.
Ten eerste: minimaliseer het relatievlak tussen Import en DirectQuery-tabellen. Elke actieve relatie over de brongrens is een potentieel serialisatiepunt. Als een SharePoint-lijst alleen als filter dient (niet als groeperingsdimensie), overweeg dan de relatie volledig te verwijderen en TREATAS binnen measures te gebruiken om het filter toe te passen. Dat geeft je controle over wanneer de cross-source overdracht plaatsvindt.
Ten tweede: maak SWITCH-measures platter. In plaats van één measure met zes CALCULATE-vertakkingen, maak je zes afzonderlijke measures en gebruik je conditionele zichtbaarheid of een calculation group om de juiste te tonen. Elke eenvoudige measure genereert één SE-query in plaats van de FE te dwingen zes te orkestreren. Het totale aantal queries kan vergelijkbaar zijn, maar de engine kan onafhankelijke measures over visuals paralleliseren.
Ten derde: stel het maximum aantal verbindingen per gegevensbron correct in. De standaard is 10. Als je rapportpagina 15 visuals heeft die elk twee DirectQuery-queries genereren, concurreren 30 queries om 10 verbindingsslots. Vergroot dit naar 20-30 op Premium/Fabric-capacities waarbij de brondatabase het gelijktijdig gebruik aankan. Dit verlaagt niet de tijd per query, maar vermindert de wachttijd.
Ten vierde: schakel query reduction in via de rapportinstellingen. Zet de Toepassen-knop aan voor slicers. Schakel cross-highlighting uit tussen visuals die verschillende storage engines aanroepen. Elke cross-filter-interactie op een composite model kan een volledige cross-source reconciliatiecyclus activeren.
MetricSign bewaakt de refresh-duur van Power BI-datasets en geeft een melding wanneer een refresh die normaal twee minuten duurt plotseling acht minuten nodig heeft. Voor composite models treedt dit refresh_delayed-signaal vaak op voordat gebruikers de prestatiedaling in de Service opmerken, zodat je het formula engine-knelpunt kunt onderzoeken vóór stakeholders vraagtekens zetten bij de cijfers in hun maandagochtend-dashboard.
Twee keer meten, één keer consolideren
De neiging om een kleine geïmporteerde tabel toe te voegen aan een DirectQuery-model is begrijpelijk. SharePoint-lijsten, Excel-referentietabellen en handmatige maptabellen zijn het bindweefsel van enterprise-rapportage. Maar elke toevoeging creëert een cross-source grens die de formula engine bij elke query moet beheren.
Voordat je een Import-tabel toevoegt aan een DirectQuery-model, voer je deze test uit: maak de measure in een puur DirectQuery-model met de referentiedata geladen in dezelfde bron. Meet de querytijd in DAX Studio. Maak dan de composite versie. Vergelijk het aantal SE-queries en de totale duur. Als de composite versie meer dan het dubbele aantal SE-queries genereert, loopt de cross-source overhead op naarmate het model groeit.
De communitydiscussie die dit artikel inspireerde, eindigde ermee dat de oorspronkelijke poster zijn SharePoint-tabellen consolideerde in het basismodel. De laadtijd in de Service daalde van ruim vijftien seconden naar minder dan drie. Er werd geen DAX herschreven. Geen measures herstructureerd. De enige wijziging was het wegnemen van de brongrens.
Dit past in een breder patroon. Import-modus met volledige VertiPaq-compressie blijft de snelste opslagmodus voor analytische queries. DirectQuery met juiste indexering en Assume Referential Integrity verwerkt real-time vereisten efficiënt. Composite models dienen een legitiem doel wanneer aggregatietabellen hoog-granulaire DirectQuery-queries versnellen. Ze gebruiken als gemakslaag om het verplaatsen van referentiedata naar de juiste bron te vermijden, werkt bijna altijd averechts zodra het rapport de Service bereikt en echte netwerklatentie een rol speelt.
De diagnostische volgorde is eenvoudig: Performance Analyzer om de trage visual te identificeren, DAX Studio Server Timings om SE-queries te tellen en een consolidatietest om de oplossing te bevestigen. De meeste teams ronden dit af in minder dan een dag.