Insight · Microsoft Fabric

    Spark and Delta Optimisation in Fabric: V-Order, OPTIMIZE and the Basics That Pay

    Most slow Fabric estates are slow for boring reasons: small files, unmaintained tables, oversized sessions. The basics - V-Order, OPTIMIZE, VACUUM, partitioning - with judgement.

    Nick de Vrye, CTOPublished 7 September 20266 min read read
    Navy Solv Systems title card reading 'Spark and Delta Optimisation' with a capacity gauge motif.

    In Short: Boring Maintenance, Real Money

    When a Fabric estate feels slow - notebooks crawling, Direct Lake visuals lagging, capacity mysteriously saturated - the cause is rarely exotic. It is almost always one of four boring things: thousands of tiny files, tables never compacted, partitioning misapplied, or Spark sessions sized on optimism. The fixes are equally boring, which is the good news: V-Order, OPTIMIZE, VACUUM, sensible partitioning and right-sized sessions are maintenance, not magic.

    This is the checklist we run first on every performance engagement, because it usually ends the engagement.

    V-Order: The Write-Time Favour to Every Reader

    V-Order is Fabric's write-time optimisation for Parquet: data is sorted and encoded so Microsoft's readers - the SQL endpoint and, above all, Power BI's Direct Lake - scan it far faster. Writes pay a modest premium; every read thereafter collects.

    The judgement call is straightforward: keep V-Order on for tables that serve BI and interactive SQL (your gold layer, especially), and consider relaxing it only for write-heavy intermediate tables nobody queries directly, where ingestion throughput is the scarce resource.

    The Small-Files Problem, and OPTIMIZE

    Delta tables accumulate files with every append, and streaming or frequent small loads accumulate thousands of them. Query engines pay per file - open, read footer, plan - so a table of 10,000 tiny files can be an order of magnitude slower than the same data in well-sized files.

    OPTIMIZE compacts. Run it on a schedule proportional to write frequency: nightly for continuously-fed tables, weekly for calmer ones, immediately after any large backfill. Fabric also offers automatic compaction behaviours on managed tables, but do not assume: inspect your busiest tables' file counts, because the small-files tax is the single most common finding in slow estates.

    VACUUM is the companion chore: it deletes unreferenced files left behind by updates and compactions, reclaiming storage. The cost is time travel - vacuumed history is gone - so set retention deliberately rather than accepting whichever default nobody read.

    Partitioning: Less Than You Think

    Partitioning splits a table into directories by column value, so filtered queries skip whole directories. It pays on large tables filtered by a low-cardinality column - date is the classic. It hurts everywhere else: partitioning a modest table by a high-cardinality column shatters it into exactly the small-files problem OPTIMIZE exists to fix.

    Rule of thumb we apply: no partitioning below tens of gigabytes; when in doubt, rely on file-level statistics and V-Order instead; and never partition to mirror an org chart.

    Sessions, Concurrency and the Bill

    Spark consumes capacity while sessions run, not while work completes. The habits that waste it: notebooks on maximum node counts "to be safe", sessions left alive between meetings, and a dozen scheduled jobs each spinning a private cluster. The remedies: default to small sessions and scale on evidence, let idle timeouts do their job, and consolidate schedules so related jobs share warm compute. High-concurrency session sharing in notebooks exists precisely for the many-small-jobs pattern.

    The satisfying part of this whole discipline: performance work and cost work are the same work. Every skipped file scan and idle minute reclaimed shows up twice - in user patience and in the capacity metrics your finance team reads.

    Sources and Further Reading

    Frequently asked

    A write-time optimisation that sorts and compresses Parquet data so Microsoft's engines - especially Power BI's Direct Lake and the SQL endpoint - read it dramatically faster. It costs a little at write time and pays on every read; for BI-serving tables it should stay on.

    Compacts many small files into fewer, well-sized ones. Streaming and frequent small appends create thousands of tiny files, and query engines pay a tax opening each; OPTIMIZE consolidates them and restores scan performance.

    It permanently removes data files no longer referenced by the table's recent history, reclaiming storage. The trade-off is time travel: after a vacuum, you can no longer restore the table to versions whose files were removed, so retention settings deserve a deliberate decision.

    Only large ones, and only on low-cardinality columns that queries genuinely filter by (a date grain is typical). Over-partitioning small tables recreates the small-files problem and is one of the most common self-inflicted slowdowns we find.

    Usually, yes. Badly maintained tables make every query scan more data, and oversized Spark sessions burn capacity units idling. Table maintenance and right-sized sessions routinely show up as capacity savings, not just faster queries.