Workload shape → VM family
| Workload | Signs in Spark UI / metrics | Family to try |
|---|---|---|
| General ETL, joins of medium tables | Balanced CPU and memory, modest spill | General purpose (D-series, newer generations) |
| Large joins/aggregations, wide tables, caching | Spill to disk, GC time high, OOM | Memory optimized (E-series) |
| CPU-heavy transforms, parsing, UDFs, ML feature work | CPU near 100%, little spill | Compute optimized (F-series) |
| Repeated reads of the same Delta data (BI, interactive) | Same files scanned again and again | Storage optimized with local NVMe (L-series) or types with large local SSD for disk cache |
| Deep learning | GPU work | GPU series (NC/ND families) with GPU runtimes |
Newer VM generations usually give better price/performance. Check which types your region offers and your vCPU quota per family before switching (see the vCPU quota Sev1 post).
Fewer large vs many small nodes
| Fewer, larger workers | Many small workers |
|---|---|
| Less shuffle over the network, more memory per executor | Finer autoscaling steps |
| Better for joins/aggregations | Better for embarrassingly parallel tasks |
| A lost node hurts more | More per-node overhead |
A common sweet spot for ETL is mid-size nodes (e.g. 8–16 cores). Test with your own jobs.
Driver sizing
- The driver needs more memory when you
collect(), broadcast large tables, or run many concurrent streams/notebooks. - For most jobs, the driver can be the same or smaller than workers.
Measure, change, measure
- Pick one heavy job. Record run time, DBU and VM cost from system tables for a few runs.
- Change one thing (family or size).
- Compare cost per run, not only runtime.
-- Cost per run for a job (DBU side; VM cost comes from Azure Cost Management)
SELECT usage_metadata.job_run_id, SUM(usage_quantity) AS dbus
FROM system.billing.usage
WHERE usage_metadata.job_id = '<job_id>'
AND usage_date >= current_date() - 30
GROUP BY 1 ORDER BY 1 DESC;
Tip
Remember both bills: Databricks DBUs and Azure VM/disk charges. A VM type with a higher hourly price can still be cheaper per run if the job finishes much faster.
Checklist
- Workload shape read from Spark UI and metrics
- VM family chosen to match
- Regional availability and quota checked
- Node count/size tested on real jobs
- Cost per run compared (DBU + VM)
- Choice enforced through cluster policies