Monitor and Optimize an Analytics Solution · Topic 4 of 5

Optimizing Lakehouse Tables and Spark Performance

DP-700 optimization: OPTIMIZE, V-Order, Z-Order and VACUUM for Delta tables, partitioning, the native execution engine, pools and efficient Spark code.

  • 5 min
In a nutshell
  • OPTIMIZE compacts files; V-Order speeds reads; Z-Order clusters by filter columns.
  • VACUUM deletes unreferenced old files; default retention is 7 days.
  • Partition only large tables on low-cardinality columns.

What it is

A lakehouse table is a folder of Parquet files plus a Delta log. It performs well when it has a moderate number of large, well-organized files. Frequent small writes, streaming and merges create many small files, and every query then pays to open them.

Spark performance depends on the same files and on the compute: pool and node sizes, session start-up, the engine used, and code that keeps work distributed.

Many small filesOPTIMIZEFewer large filesVORDERFaster readsVACUUMOld files removed

How it works

Optimize a lakehouse table

TechniqueWhat it doesWhen to use
OPTIMIZECompacts small files into larger onesTables written by frequent small batches, streaming or merges
V-OrderWrite-time Parquet optimization (sorting, encoding, compression) that speeds up reads by Direct Lake, the SQL analytics endpoint and SparkTables read often, especially by Power BI
ZORDER BYCo-locates rows with similar values so queries skip filesHigh-cardinality columns used in filters, such as customer_id
VACUUMDeletes files no longer referenced by the Delta log and older than the retention periodRegularly, to cut storage; it limits time travel
PartitioningSplits the table into folders by a columnLarge tables filtered by a low-cardinality column such as year
Optimize writeSpark setting that produces fewer, larger files at write timeWrite paths that would otherwise create many small files
%%sql
OPTIMIZE sales_orders ZORDER BY (customer_id) VORDER;
VACUUM sales_orders RETAIN 168 HOURS;

The default retention for VACUUM is 7 days (168 hours). A shorter period removes the files that time travel and long-running readers need, so Delta blocks it unless you deliberately disable the safety check.

You can also run these from the lakehouse explorer: choose Maintenance on a table to run OPTIMIZE (optionally with V-Order) and VACUUM with a retention threshold. A notebook or pipeline can schedule maintenance for many tables.

Partition only large tables, on columns with few distinct values. Partitioning by a high-cardinality column such as order_id or a timestamp creates thousands of tiny files and makes queries slower.

Optimize Spark performance

Compute choices

SettingEffect
Starter poolSessions start in seconds; good for interactive and short jobs
Custom poolRight-size nodes and autoscale for heavy jobs
Dynamic allocationAdds and removes executors as the job needs them
High concurrencyNotebooks share a session, so they skip start-up time
Native execution engineRuns Spark SQL and DataFrame operations in a vectorized C++ engine; no code changes; falls back to standard Spark for unsupported operations

Enable the native execution engine in an environment's acceleration settings, or for one session:

%%configure
{
    "conf": {
        "spark.native.enabled": "true"
    }
}

Code choices

  • Filter and select columns early, so Delta can skip files and Parquet reads fewer columns.
  • Broadcast small dimension tables in joins, so the large table is not shuffled.
  • Prefer built-in functions to Python UDFs, which move data between the JVM and Python.
  • cache() a DataFrame only when it is reused several times, and unpersist it after.
  • Avoid collect() and toPandas() on large data; write results to a table.
  • Repartition on a better key when one task runs far longer than the rest (data skew).
from pyspark.sql import functions as F

fact = spark.read.table("fact_sales").where(F.col("order_date") >= "2026-01-01")
dim = spark.read.table("dim_product").select("product_key", "category")

result = (fact.join(F.broadcast(dim), "product_key")
    .groupBy("category")
    .agg(F.sum("amount").alias("revenue")))

Adaptive query execution is on by default in Spark 3, so Spark already coalesces shuffle partitions and can switch join strategies at run time. Use the Spark UI to see slow stages, spills to disk and skewed tasks.

A worked example

A streaming job appends to iot_readings every minute. After three months, queries that took seconds take minutes, and the table folder holds hundreds of thousands of small files.

A nightly notebook runs OPTIMIZE iot_readings ZORDER BY (device_id) VORDER and a weekly VACUUM with the default retention. Queries filtering by device now skip most files. The team also turns on the native execution engine in the environment for the aggregation notebooks.

How the exam asks about this

  • "A Delta table has many small files and slow queries." Run OPTIMIZE.
  • "Improve Direct Lake and SQL endpoint read performance of a lakehouse table." Apply V-Order.
  • "Remove unreferenced files to reduce storage while keeping 7 days of time travel." VACUUM with the default 168 hour retention.

What to remember for the exam

  • OPTIMIZE compacts files; V-Order speeds reads; Z-Order clusters by filter columns.
  • VACUUM deletes unreferenced old files; default retention is 7 days.
  • Partition only large tables on low-cardinality columns.
  • The native execution engine accelerates Spark with no code changes.
  • Broadcast small tables, avoid Python UDFs and collect(), and check the Spark UI for skew.
Watch out

Running VACUUM with a very short retention breaks time travel and can fail queries or streams still reading older files. Keep the default unless you have a strong reason.

Common mistakes

Partitioning by date and hour on a small table. It multiplies small files; a small table needs no partitions.

Expecting V-Order to fix a small file problem. V-Order organizes data within files; OPTIMIZE reduces the number of files.

Scaling up nodes before fixing code. A collect(), a Python UDF or a skewed join usually costs more than node size.

Check yourself

  • Which command compacts many small files in a Delta table?

    OPTIMIZE, optionally with ZORDER BY and VORDER.

  • What is the default retention period for VACUUM?

    7 days (168 hours); shorter values are blocked by a safety check unless it is disabled.

  • How do you speed up a join between a large fact table and a small dimension table in Spark?

    Broadcast the small table, for example with F.broadcast(dim), so the large table is not shuffled.

Topic 4 of 5 in Monitor and Optimize an Analytics Solution

Test yourself on Monitor and Optimize an Analytics Solution

The full Microsoft DP-700 question bank has 645 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by Microsoft. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.