Quick Answer
The four knobs that determine Direct Lake performance are: V-Ordered Parquet files, appropriate Fabric SKU sizing, Delta table optimization (OPTIMIZE and VACUUM), and DAX patterns that avoid calculated columns or unsupported features. Get these four right and Direct Lake matches Import-mode query performance with zero refresh latency. Get them wrong and you fall back to DirectQuery on every visual.
1. How Direct Lake Actually Works
Direct Lake skips the traditional refresh step. When a query arrives, the analysis services engine identifies which column segments it needs, pages them in from OneLake Parquet files, and evaluates DAX in memory. Three concepts are essential:
- Framing: the semantic model is bound to a specific version of the underlying Delta tables. When Delta tables are updated, the model must be re-framed to see new data. Framing is an administrative operation that happens in seconds.
- Column segments: Parquet row groups map to column segments in the engine. A typical row group is 1 million rows. Queries read whole segments, not individual rows.
- Paging: segments stay in memory after first load, and inactive segments are evicted under memory pressure. The engine is effectively a cache on top of OneLake.
When any of these components misalign (stale frame, unsupported segment format, memory overflow), Direct Lake falls back to DirectQuery silently.
2. Parquet File Preparation
Enable V-Order
Every Parquet file written by Fabric defaults to V-Order enabled. When writing from external engines, configure V-Order explicitly.
# Spark in Fabric notebook
spark.conf.set("spark.sql.parquet.vorder.enabled", "true")
df.write.format("delta").save("Tables/Sales")
# Post-hoc optimization of existing tables
%%sql
OPTIMIZE Sales VORDERRegular OPTIMIZE and VACUUM
Delta tables accumulate small files after streaming writes or frequent incremental updates. Run OPTIMIZE weekly to compact files into larger V-Ordered segments. Run VACUUM monthly to reclaim storage from deleted files. Without these, Direct Lake performance degrades 20 to 40 percent over time.
%%sql
-- Compact small files with V-Order
OPTIMIZE Sales VORDER;
-- Reclaim deleted file space (default 7-day retention)
VACUUM Sales RETAIN 168 HOURS;3. Partitioning Strategy
Delta table partitioning lets the query engine prune irrelevant partitions before paging segments into memory. For large fact tables, partition by a low-cardinality column that aligns with typical filter patterns.
- Date partitioning: partition by year or year-month for tables where queries typically filter by date. Sales tables almost always benefit from year partitioning.
- Region or business unit partitioning: for multi-tenant data where queries are naturally scoped per tenant, partitioning by tenant keeps each query within one partition.
- Avoid over-partitioning: more than a few hundred partitions creates small-file problems and hurts compaction. Year or quarter partitioning is almost always preferable to day partitioning for analytical workloads.
# Partition a new table by year
df.write \
.format("delta") \
.partitionBy("Year") \
.option("delta.autoOptimize.optimizeWrite", "true") \
.option("parquet.vorder.enabled", "true") \
.save("Tables/Sales")4. Memory Budget Per SKU
Each Fabric SKU has a memory budget that caps the amount of Direct Lake content held in memory concurrently.
| SKU | Max Memory (GB) | Max Rows per Table | Parallel Queries |
|---|---|---|---|
| F64 | 25 | 1.5B | ~24 |
| F128 | 50 | 3B | ~48 |
| F256 | 100 | 6B | ~96 |
| F512 | 200 | 12B | ~192 |
| F1024 | 400 | 24B | ~384 |
When concurrent queries exceed the memory budget, Direct Lake evicts segments and pages in new ones, which triggers more I/O. For consistent performance, size the SKU so that the working set of column segments fits in memory with headroom for burst queries.
5. DAX Patterns That Stay In Direct Lake
Certain DAX features force fallback. Avoid them in Direct Lake models.
- Calculated columns on Direct Lake tables: any calculated column forces the full table to materialize in memory, defeating the purpose of Direct Lake.
- Calculated tables: the evaluation result materializes at frame time, occupying memory. Prefer composite models where calculated tables live in an Import-mode extension.
- Complex RLS with TREATAS over large dimensions: RLS expressions that call TREATAS with more than 1 million rows can degrade performance. Simpler RLS patterns using direct column comparisons fare better.
- DirectQuery sources through composite model: a composite model with one Direct Lake table and one DirectQuery table will cause queries that join the two to fall back to DirectQuery for the joined portion.
Validate every DAX measure with Performance Analyzer. Any measure that shows Direct Lake on SQL instead of Direct Lake on Parquet is falling back. Rewrite the measure or adjust the model.
6. Framing and Freshness
Direct Lake binds the model to a specific Delta table version through framing. By default, the model reframes automatically when queries arrive and new data is available. For very high-throughput write scenarios, you may want to manually control framing.
# Semantic link Python API for explicit framing
import sempy.fabric as fabric
fabric.refresh_dataset(
workspace="Sales Workspace",
dataset="Sales Analytics",
refresh_type="full",
commit_mode="transactional"
)Explicit framing is useful for transactional workflows where you want to hold a consistent view of data during a reporting window. For most analytical use cases, automatic framing is sufficient.
7. Monitoring and Diagnostics
Three tools are essential for Direct Lake diagnostics:
- Performance Analyzer (Power BI Desktop): shows storage engine type for each visual. Look for Direct Lake on Parquet in the trace, which means the query stayed in Direct Lake.
- DAX Studio Server Timings: connect to the XMLA endpoint and trace individual queries to identify fallback triggers and slow segments.
- Fabric Capacity Metrics app: shows overall fallback rate, memory pressure, and which datasets consume the most CU.
Build a recurring diagnostic process: once per month, sample 20 percent of queries across production datasets, measure fallback rate, and tune the top offenders. This prevents gradual degradation and keeps Direct Lake performance consistent. For deeper diagnostics workflow, see our Capacity Metrics app guide.
Frequently Asked Questions
What is Direct Lake mode?
Direct Lake is a Power BI storage mode that reads Delta Parquet files directly from OneLake into the analysis services in-memory engine on demand. It combines the query performance of Import mode (data is processed in memory) with the freshness of DirectQuery mode (data is read at query time from the source). There is no scheduled refresh step. Direct Lake is available only in Microsoft Fabric workspaces on F64 or higher capacity, or on PPU with Fabric trial.
How does Direct Lake differ from DirectQuery?
DirectQuery sends SQL queries to an underlying source database and aggregates results outside the Power BI engine. Direct Lake reads raw Parquet column segments into memory and evaluates DAX using the same in-memory engine as Import mode. The result is that Direct Lake performance is comparable to Import, while DirectQuery is usually 3 to 10 times slower. Direct Lake also supports all DAX functions, while DirectQuery has function-level limitations on complex time intelligence and iterators.
When does Direct Lake fall back to DirectQuery?
Direct Lake falls back to DirectQuery on a per-query basis when specific conditions are not met. Common fallback triggers include: the Parquet file is not optimized with V-Order, the table or column set exceeds the memory budget for the capacity SKU, the row count exceeds SKU limits, certain features like calculated columns on imported tables are used, or the query includes features not yet supported in Direct Lake. Fallback is transparent but has performance implications. A report that runs entirely in Direct Lake mode typically renders in 1 to 3 seconds. A report that falls back to DirectQuery for some visuals may render in 5 to 15 seconds.
What is V-Order and why does it matter?
V-Order is a Microsoft-specific optimization applied to Delta Parquet files that reorders rows within column segments to maximize compression and accelerate the analysis services storage engine. V-Ordered files are the requirement for Direct Lake to read them natively. Files not written with V-Order will cause Direct Lake to fall back to DirectQuery. V-Order is enabled by default in Fabric workspaces. When writing Parquet from external tools (Synapse, Databricks, Spark outside Fabric), either enable V-Order via Microsoft extensions or run OPTIMIZE with VORDER in Fabric after landing the data.
How much memory does a Direct Lake model use?
Direct Lake loads column segments into memory on demand. Only columns queried recently and currently needed occupy memory. A semantic model with 500 columns but regular queries on 30 of them will consume memory only for those 30. When a query references a new column, the segment is paged in from OneLake. Inactive segments are evicted under memory pressure. The effective memory footprint is typically 5 to 20 percent of an equivalent Import model containing the same underlying data.
Can I mix Direct Lake with Import tables?
Yes, using composite models. A common pattern is Direct Lake on large fact tables (100 million+ rows) combined with Import mode on small dimension tables (up to 1 million rows). The Import dimensions take full advantage of the analysis services cache, while the Direct Lake facts stay fresh without scheduled refresh. This hybrid approach gives near-Import performance on the small tables and Direct Lake freshness on the large tables.
What row count limits apply to Direct Lake?
Row count limits are tied to Fabric capacity SKU. F64 supports up to 1.5 billion rows per table. F128 supports 3 billion. F256 supports 6 billion. F512 supports 12 billion. F1024 supports 24 billion. When a table exceeds the limit, queries against it fall back to DirectQuery. Memory limits are separate and depend on the total size of column segments loaded concurrently. For tables larger than these limits, partitioning by date or by business unit and querying subsets through RLS can keep each query within the supported row range.
How do I detect Direct Lake fallback in production?
Microsoft exposes fallback telemetry through the Fabric Capacity Metrics app and through query diagnostics in Power BI Desktop Performance Analyzer. In Performance Analyzer, an expanded trace shows the storage engine type used for each query: Direct Lake on Parquet, Direct Lake on SQL (fallback), or DirectQuery. In production monitoring, query the admin Get-PowerBIActivityEvent API for dataset operations and filter for Direct Lake fallback events. Set an alert when fallback percentage exceeds 10 percent of queries, which usually indicates a model or data shape problem requiring tuning.
Tuning a Slow Direct Lake Model?
Our consultants diagnose fallback patterns, re-optimize Parquet layouts, and rewrite DAX to keep queries in-memory. Contact us for a Direct Lake assessment.