azure databricks vs microsoft fabric is the decision that lands on nearly every Azure data team's roadmap in 2026, and it is not really a feature bake-off — it is a choice between two philosophies of how a lakehouse should be operated. Azure Databricks hands the engineer the compute: you size Spark clusters, tune Photon, wire Delta Lake tables, and govern them through Unity Catalog, all as code you own. Microsoft Fabric hides the compute behind an integrated SaaS surface: you provision one capacity, drop data into OneLake, and every engine — Spark, T-SQL, Power BI's Direct Lake — reads the same Delta Parquet without you touching a cluster.
The confusing part is that both products write the same files. A Delta table produced by a Databricks job and a Delta table produced by a Fabric Lakehouse are byte-compatible Parquet plus a transaction log sitting on Azure Data Lake Storage Gen2. So the storage floor is shared and the real difference is everything above it — who controls the compute, how governance is expressed, how you are billed, and where Power BI gets its speed. This guide walks the four things an interviewer or an architecture review will actually probe — the Databricks engine stack, the Fabric SaaS stack, the OneLake shortcut layer that lets them interoperate, and the DBU-versus-capacity cost models — and pairs each with a Solution-Tail interview answer: code, a step-by-step trace, an output table, then a concept-by-concept breakdown of why it works.
When you want hands-on reps immediately after reading, drill the data-warehouse practice library →, rehearse the load and modelling patterns on the ETL practice set →, and tune the read paths on the optimization practice set →.
On this page
- Why the Azure lakehouse choice matters in 2026
- Azure Databricks — the engineer's lakehouse
- Microsoft Fabric — the integrated SaaS lakehouse
- OneLake, shortcuts & interoperability
- Choosing between them — cost & fit
- Cheat sheet — Azure lakehouse recipes
- Frequently asked questions
- Practice on PipeCode
1. Why the Azure lakehouse choice matters in 2026
The choice is engineer-controlled compute versus integrated SaaS — everything else follows from that one axis
The one-sentence invariant: Databricks gives you the compute to operate, Fabric gives you an outcome to consume, and both land the same Delta Parquet on ADLS Gen2. Once you see that both products persist open Delta tables on the same storage layer, the argument stops being "which lake is better" and becomes "who should own the compute and governance plane above the lake" — and that is a team-and-cost question, not a file-format one.
The two philosophies.
- Databricks — a platform you operate. You provision clusters (or serverless SQL warehouses), choose runtime versions, tune Photon and autoscaling, and write pipelines as notebooks or jobs. Control is the product: you can profile a Spark stage, pin a cluster policy, and shape cost to the workload.
- Fabric — a platform you consume. You buy one capacity (an F-SKU), and the Lakehouse, Warehouse, Data Factory, and Power BI experiences share it. There is no cluster to size; Microsoft runs the engines and meters your usage against Capacity Units.
- Shared floor. Both write Delta tables to ADLS Gen2 (OneLake is an ADLS Gen2 endpoint). The table a Databricks job writes and the table a Fabric Lakehouse writes are the same on disk, which is exactly why shortcuts and mirroring can bridge them.
What actually differs above the storage.
- Compute control. Databricks: you tune it. Fabric: Microsoft tunes it, you pick a capacity size.
-
Governance model. Databricks centralizes on Unity Catalog (
catalog.schema.table, lineage, fine-grained grants). Fabric governs through workspaces, item permissions, and OneLake security, integrated with Microsoft Entra ID. - BI acceleration. Fabric's Direct Lake lets Power BI read Delta from OneLake with import-like speed and no data copy. Databricks reaches Power BI through DirectQuery or import against a SQL warehouse.
- Billing unit. Databricks bills DBUs on top of the cloud VM cost; Fabric bills a fixed capacity measured in Capacity Units with smoothing and bursting.
What interviewers listen for.
- Do you say "both write Delta on ADLS Gen2, so the difference is the control plane, not the storage" early? — senior signal.
- Do you frame it as "engineer-controlled compute vs integrated SaaS" rather than a feature checklist? — required framing.
- Do you know Direct Lake is the reason Fabric feels fast for Power BI, and that it is neither import nor DirectQuery? — the detail that separates readers from users.
- Do you reach for OneLake shortcuts to avoid copying data between the two, instead of duplicating tables? — the one-copy instinct.
Worked example — the same Delta table, two engines
Detailed explanation. The cleanest way to feel the shared-floor point is to write a Delta table once and read it from the other engine with zero conversion. A Databricks job writes sales as Delta to a path; a Fabric Lakehouse points a shortcut at that path and queries it as if it were native. No export, no copy, no format translation — because it was Delta Parquet the whole time.
Question. A Databricks job wrote a Delta table to abfss://data@lake.dfs.core.windows.net/sales. Show that Fabric can read it without copying, and name what makes that possible.
Input.
| step | who | action |
|---|---|---|
| 1 | Databricks | writes Delta table sales to ADLS Gen2 |
| 2 | Fabric | creates a OneLake shortcut to that folder |
| 3 | Fabric | queries sales via the SQL analytics endpoint |
Code.
data = spark.read.format("json").load("/mnt/raw/sales") # Databricks side
(data.write.format("delta").mode("overwrite") # write once, as open Delta
.save("abfss://data@lake.dfs.core.windows.net/sales"))
-- Fabric Lakehouse: a shortcut named `sales` now points at that ADLS folder.
-- Read it through the SQL analytics endpoint with plain T-SQL, no copy:
SELECT region, SUM(amount) AS revenue
FROM sales
GROUP BY region;
Step-by-step explanation. Databricks writes standard Delta (Parquet data files plus a _delta_log transaction log). Fabric's OneLake shortcut is a pointer, not a copy, so the folder appears inside the Lakehouse as a table. Fabric's SQL analytics endpoint reads the Delta log to resolve the current files and answers the GROUP BY directly against the same Parquet Databricks wrote. Neither engine converted anything.
Output.
| what happened | value |
|---|---|
| data copied | none (shortcut is a virtual pointer) |
| format | Delta Parquet, read natively by both engines |
| Fabric read path | SQL analytics endpoint over the shortcut |
| enabling fact | Delta on ADLS Gen2 is the shared floor |
Rule of thumb. If the debate is "Databricks or Fabric," remember they are not fighting over the storage — they are two control planes over the same Delta lake, so pick the one whose compute model and billing fit your team.
2. Azure Databricks — the engineer's lakehouse
Spark, Photon, Delta Lake and Unity Catalog are the four pillars — learn these and you can reason about any Databricks workload
Azure Databricks is a first-party Azure service (co-engineered with Microsoft) that packages the Databricks lakehouse: an Apache Spark runtime, the Photon vectorized engine, Delta Lake as the table format, and Unity Catalog as the governance layer. An interviewer who asks "walk me through the Databricks stack" wants those four, in the order compute → storage → governance → orchestration.
The compute layer.
- Apache Spark. The distributed engine underneath everything — DataFrame and SQL APIs, executed across a cluster of worker nodes you size (or serverless, where Databricks sizes it).
- Photon. A vectorized query engine written in C++ that transparently accelerates Spark SQL and DataFrame operations. You do not rewrite code; you enable Photon on the cluster and eligible operators run faster and cheaper per DBU.
- Clusters and DBUs. An all-purpose cluster backs interactive notebooks; a job cluster spins up for a scheduled run and tears down after. Cost is a DBU rate multiplied by runtime, plus the underlying Azure VM cost — two line items, not one.
The storage layer — Delta Lake.
-
ACID on object storage. Delta wraps Parquet data files with a
_delta_log(JSON + checkpoint) that gives atomic commits, so concurrent writers never expose a half-written table. -
Time travel.
VERSION AS OF/TIMESTAMP AS OFlet you query or restore an earlier snapshot — invaluable for audit and for recovering a bad load. -
MERGE,OPTIMIZE,ZORDER.MERGEgives SQL upserts;OPTIMIZEcompacts small files;ZORDER BYco-locates values of a column so file-skipping prunes more data on filtered reads.
The governance layer — Unity Catalog.
-
Three-level namespace. Objects are addressed
catalog.schema.table, so one metastore can serve many workspaces with consistent naming. -
Fine-grained access.
GRANT SELECT ON TABLE ..., row filters, and column masks are declared once and enforced across Spark, SQL, and downstream tools. - Lineage and discovery. Unity Catalog captures table- and column-level lineage automatically, which is what an auditor asks for and a script cannot fake.
Orchestration on top.
- Notebooks for interactive, multi-language (Python/SQL/Scala/R) development.
- Jobs / Workflows for scheduled, multi-task DAGs with retries and alerts.
- Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) for declarative ETL where you describe the target tables and expectations and Databricks manages the dependency graph and incremental refresh.
Worked example — a Delta upsert with MERGE
Detailed explanation. The single most-used Databricks write pattern is an upsert into a Delta table with MERGE INTO. It is the engineer-controlled equivalent of "keep the current state of a dimension": match on a key, update the rows that changed, insert the rows that are new, all in one atomic transaction against the Delta log.
Question. A customers Delta table holds current customer state. A staging table updates carries changed and new rows keyed by customer_id. Write the MERGE that updates existing customers and inserts new ones in one atomic commit.
Input.
| table | rows (customer_id: tier) |
|---|---|
customers (target) |
1: silver, 2: gold |
updates (source) |
2: platinum, 3: silver |
Code.
MERGE INTO customers AS t
USING updates AS s
ON t.customer_id = s.customer_id
WHEN MATCHED THEN
UPDATE SET t.tier = s.tier, t.updated_at = s.updated_at
WHEN NOT MATCHED THEN
INSERT (customer_id, tier, updated_at)
VALUES (s.customer_id, s.tier, s.updated_at);
Step-by-step explanation. Databricks scans updates and joins to customers on customer_id. Customer 2 matches, so the WHEN MATCHED branch updates its tier from gold to platinum. Customer 3 has no match, so the WHEN NOT MATCHED branch inserts it. Customer 1 appears in neither source row, so it is untouched. The whole operation commits as one Delta transaction, so a reader sees either the old or the new state, never a partial one.
Output.
| customers after MERGE | tier |
|---|---|
| 1 | silver (unchanged) |
| 2 | platinum (updated) |
| 3 | silver (inserted) |
Rule of thumb. Any time the same business entity can appear again with new values, reach for Delta MERGE on the key — an append would duplicate it, and hand-written delete-then-insert breaks atomicity.
Azure Databricks interview question on read performance
Question. A 2 TB Delta events table is filtered almost every query by event_date and often by customer_id, but reads scan far more files than they should. Which two Delta maintenance commands fix this, and what does each do?
Solution Using OPTIMIZE with ZORDER and partitioning
Code.
-- 1. Partition the table by the coarse, low-cardinality filter column.
-- (Set at create time; partitioning by event_date prunes whole folders.)
CREATE TABLE events (
event_id BIGINT, customer_id BIGINT, event_date DATE, payload STRING
) USING DELTA
PARTITIONED BY (event_date);
-- 2. Compact small files AND cluster by the high-cardinality filter column
-- so file-level statistics let the reader skip non-matching files.
OPTIMIZE events
WHERE event_date >= '2026-01-01'
ZORDER BY (customer_id);
Step-by-step trace.
| stage | before | after |
|---|---|---|
| partitioning | reader scans all dates | reader opens only matching event_date folders |
| small files | thousands of tiny Parquet files | compacted into ~1 GB files |
| ZORDER |
customer_id scattered across files |
co-located, so min/max stats skip files |
| filtered read | scans ~1900 files | scans ~40 files |
-
Partitioning by
event_dateturns the coarse date filter into directory pruning: the engine never opens folders outside theWHERErange. -
OPTIMIZEcompacts many small files into few large ones, cutting per-file overhead and improving scan throughput. -
ZORDER BY (customer_id)physically co-locates rows with similarcustomer_id, so each file's min/max statistics are tight and Delta's data-skipping prunes files that cannot contain the value. - Together, a query filtering
event_dateandcustomer_idreads a small fraction of the table instead of scanning all 2 TB.
Output:
| metric | before | after |
|---|---|---|
| files scanned (typical query) | ~1900 | ~40 |
| bytes read | ~2 TB | ~45 GB |
| effect | full-ish scan | pruned, data-skipped read |
Why this works — concept by concept:
- Partition pruning — partitioning by a low-cardinality column lets the planner skip whole directories before reading any Parquet, the cheapest possible filter.
-
File compaction —
OPTIMIZEreplaces many small files with few large ones, so fixed per-file costs (open, footer read) stop dominating the scan. - ZORDER data-skipping — clustering a high-cardinality column tightens per-file min/max statistics so Delta can prune files that cannot match the predicate.
- Engineer control — these are levers you pull on Databricks; the point of the platform is that read performance is tunable, not opaque.
- Cost — maintenance is O(rewritten bytes) once, but every subsequent filtered read drops from O(table) to O(matching files), a durable win.
Warehouse
Topic — data-warehouse
Lakehouse and warehouse modelling problems
3. Microsoft Fabric — the integrated SaaS lakehouse
OneLake, dual engines, and Direct Lake are the mental model — one lake, many engines, one capacity
Microsoft Fabric is an end-to-end SaaS analytics platform where every workload — Data Factory, Spark, T-SQL warehousing, real-time, and Power BI — runs on one shared capacity over one logical lake called OneLake. An interviewer who asks "how does Fabric fit together" wants OneLake at the center, the two compute engines that sit on it, and Direct Lake as the reason Power BI is fast.
OneLake — the one lake per tenant.
- One logical lake. OneLake is provisioned automatically for the tenant, like OneDrive for data. It is built on ADLS Gen2 and stores tables as Delta Parquet, so it is the same open format Databricks uses.
- Workspaces and items. Data lives in workspaces as items — a Lakehouse (files + Delta tables) or a Warehouse (T-SQL managed tables). Both persist to OneLake.
- One copy. The design goal is that ingesting once makes the data usable by every engine, so you avoid the copy-per-tool sprawl of a classic stack.
The two compute engines.
- Lakehouse (Spark). Notebooks and Spark job definitions run PySpark/Spark SQL over OneLake Delta tables — the code-first surface, closest to Databricks in feel.
-
Warehouse (T-SQL). A fully managed, ACID T-SQL engine with a familiar
CREATE TABLE/INSERT/CTASsurface for SQL-first teams; it also writes Delta to OneLake. - SQL analytics endpoint. Every Lakehouse automatically exposes a read-only T-SQL endpoint over its Delta tables, so BI and SQL users query the lake without Spark.
Ingestion — mostly low-code.
- Dataflows Gen2. A Power Query (M) experience for visual, low-code transformation — the tool a business-leaning analyst reaches for.
- Data Factory pipelines. Orchestration and copy activities inside Fabric for code-optional ETL/ELT.
- Notebooks remain available when you need real code, so Fabric spans low-code to pro-code on one surface.
Direct Lake — the Power BI accelerator.
- Neither import nor DirectQuery. Direct Lake loads Delta Parquet columns from OneLake directly into the Power BI engine's memory on demand, giving import-like speed without scheduled imports and without translating queries to a remote source.
- No data copy. Because it reads OneLake in place, there is no separate dataset refresh copying data around; the report reflects the lake.
- Fallback. If a query hits an unsupported feature, Direct Lake can fall back to DirectQuery, so correctness is preserved while most queries stay fast.
Worked example — build a table with the T-SQL Warehouse
Detailed explanation. The clearest way to feel Fabric's SaaS nature is to build a table with no cluster in sight. In a Fabric Warehouse you write ordinary T-SQL; the engine, the scaling, and the Delta persistence to OneLake are all handled for you. A CREATE TABLE AS SELECT (CTAS) reads source rows and materializes an aggregate — the same shape you would write in any SQL warehouse.
Question. In a Fabric Warehouse, build a daily_revenue table from a sales table using CTAS, aggregating revenue per day. Show that no compute is provisioned by you.
Input.
| sales (source) | sale_date | amount |
|---|---|---|
| row 1 | 2026-03-01 | 100 |
| row 2 | 2026-03-01 | 40 |
| row 3 | 2026-03-02 | 70 |
Code.
-- Fabric Warehouse: plain T-SQL, no cluster to size.
CREATE TABLE daily_revenue AS
SELECT
sale_date,
SUM(amount) AS revenue,
COUNT(*) AS order_count
FROM sales
GROUP BY sale_date;
Step-by-step explanation. The Warehouse engine reads sales from OneLake, groups by sale_date, and computes the sum and count. CTAS both defines and populates daily_revenue in one statement, and the engine persists it as a Delta table in OneLake. You never chose a node count or started a cluster — capacity is the only thing you provisioned, and Microsoft schedules the query against it.
Output.
| daily_revenue | revenue | order_count |
|---|---|---|
| 2026-03-01 | 140 | 2 |
| 2026-03-02 | 70 | 1 |
Rule of thumb. In Fabric you provision capacity, not compute — if you find yourself wanting to size a cluster, you are thinking in Databricks terms; in Fabric that knob does not exist by design.
Microsoft Fabric interview question on Power BI performance
Question. A stakeholder complains that Power BI reports are either stale (scheduled import) or slow (DirectQuery to a warehouse). The data already lives as Delta in OneLake. Which Fabric feature removes both problems, and how does it work?
Solution Using a Direct Lake semantic model
Code.
Fabric Lakehouse `sales_lh` holds a Delta table `fact_sales` in OneLake.
1. From the Lakehouse SQL analytics endpoint, create a semantic model
(dataset) on `fact_sales` and related dimensions.
2. Set the storage mode to **Direct Lake** (the default for a model built
on OneLake Delta tables) — not Import, not DirectQuery.
3. Build the Power BI report on that semantic model.
-- The model exposes measures over the OneLake Delta table, e.g.:
-- Total Revenue = SUM(fact_sales[amount])
-- These columns are paged into memory from OneLake Parquet on demand.
SELECT * FROM fact_sales; -- served from OneLake, no import copy
Step-by-step trace.
| aspect | Import | DirectQuery | Direct Lake |
|---|---|---|---|
| data location | copied into dataset | stays in source | stays in OneLake |
| freshness | as of last refresh | always live | reflects OneLake |
| speed | fast (in-memory) | slow (remote query) | fast (columns paged to memory) |
| copy made? | yes | no | no |
- A Direct Lake semantic model points at the
fact_salesDelta table already in OneLake — there is nothing to import. - When a visual queries a measure, Power BI pages the needed Delta Parquet columns straight into the analytics engine's memory, so scans are in-memory fast like Import.
- Because it reads OneLake in place, the report reflects the latest committed Delta version without a scheduled refresh, removing the staleness of Import.
- If a query touches an unsupported construct, the model transparently falls back to DirectQuery, so results stay correct while typical queries stay fast.
Output:
| problem | resolved by Direct Lake? | why |
|---|---|---|
| stale data (Import) | yes | reads current OneLake Delta, no refresh lag |
| slow queries (DirectQuery) | yes | columns paged to memory, in-memory speed |
| duplicate storage | yes | no import copy; one copy in OneLake |
Why this works — concept by concept:
- OneLake as the single copy — because the Delta table already lives in OneLake, Direct Lake has nothing to copy and no source to remotely query.
- Column paging — loading only the Parquet columns a query needs into memory gives Import-class speed without materializing the whole dataset up front.
- No refresh lag — reading the lake in place means the report tracks the latest committed Delta version, killing the staleness of scheduled Import.
- DirectQuery fallback — the safety net keeps results correct on unsupported features, so "fast" never costs you "wrong."
- Cost — Direct Lake trades a scheduled-refresh copy for on-demand column paging metered against capacity; cost scales with columns and rows actually read, O(queried data), not O(table).
Warehouse
Topic — data-warehouse
Warehouse and semantic-model problems
4. OneLake, shortcuts & interoperability
Shortcuts virtualize data so Databricks and Fabric read one copy — the interop story is "point, do not copy"
The most important architectural feature for a team that runs both products is the OneLake shortcut: a symbolic pointer that makes external data appear inside OneLake without moving or duplicating it. This is what lets Databricks and Fabric cooperate over a single physical copy instead of forking your data into two lakes that drift apart.
What a shortcut is.
- A pointer, not a copy. A shortcut references data in another location and surfaces it in a Fabric Lakehouse as if it were local. Reads go to the source; nothing is duplicated.
- Internal and external. Internal shortcuts point elsewhere in OneLake; external shortcuts point at ADLS Gen2, Amazon S3, Google Cloud Storage, or Dataverse, so multi-cloud data lands in one logical lake.
- Delta-aware. If the target folder is a Delta table, Fabric reads it as a table — which is exactly the Databricks-writes/Fabric-reads bridge from Section 1.
Format interoperability — Delta and Iceberg.
- Metadata virtualization. Fabric can present a Delta table as Iceberg (and vice-versa) through metadata virtualization (Apache XTable / the UniForm approach), so an engine that speaks only one format still reads the one physical copy.
- One physical copy, many logical views. The Parquet data is written once; the different table-format logs are metadata over it, so you are not paying to store the data twice.
Bridging Databricks and Fabric.
- Shortcut to Unity Catalog data. A Fabric shortcut can target the ADLS location of a Databricks/Unity Catalog Delta table, exposing it in OneLake without an ETL copy.
- Mirroring. Fabric mirroring continuously replicates an external database or catalog into OneLake as Delta, giving a near-real-time local copy when a live pointer is not enough.
- Governance still applies. Surfacing data through a shortcut does not bypass permissions; access is still governed on both sides, so interop does not mean ungoverned.
Worked example — a shortcut instead of a copy pipeline
Detailed explanation. The everyday interop pattern is replacing a nightly copy job with a shortcut. Instead of an ETL pipeline that reads a Databricks Delta table and writes a duplicate into OneLake, you create one shortcut and the table is simply there, always current, with no pipeline to run or storage to double-pay.
Question. A Databricks team maintains a curated dim_customer Delta table on ADLS Gen2. The Fabric team needs it in their Lakehouse for Power BI. Compare a copy pipeline with a shortcut and show the shortcut definition.
Input.
| approach | copies data? | freshness | storage cost |
|---|---|---|---|
| nightly copy pipeline | yes | up to 24 h stale | pays twice |
| OneLake shortcut | no | always current | pays once |
Code.
// Fabric OneLake shortcut definition (external ADLS Gen2 target).
// The Databricks-written Delta table appears in the Lakehouse as `dim_customer`.
{
"name": "dim_customer",
"target": {
"adlsGen2": {
"location": "https://lake.dfs.core.windows.net/curated",
"subpath": "/dim_customer",
"connectionId": "<entra-governed-connection>"
}
}
}
Step-by-step explanation. The shortcut names a table (dim_customer) and points at the ADLS Gen2 folder where Databricks writes that Delta table. Fabric resolves the Delta log at read time, so the Lakehouse always sees the latest committed version — no schedule, no copy. The connection is governed through Microsoft Entra, so access control is preserved. A Power BI Direct Lake model can now sit on dim_customer with zero duplicated storage.
Output.
| outcome | value |
|---|---|
| pipeline to maintain | none (shortcut replaces the copy job) |
| data copies | 1 (the Databricks copy; Fabric points at it) |
| freshness | live — reflects latest Delta commit |
| Power BI | Direct Lake reads the shortcut in place |
Rule of thumb. Before you write a pipeline to move a table between Databricks and Fabric, ask whether a shortcut would do — if both sides speak Delta on ADLS Gen2, copying is usually wasted storage and a source of drift.
Azure lakehouse interview question on avoiding duplicate copies
Question. Your org runs Databricks for engineering and Fabric for BI. A naive design copies every curated Delta table from the Databricks lake into OneLake nightly. Redesign it so there is one physical copy, and explain the trade-off you accept.
Solution Using OneLake shortcuts with mirroring for the exceptions
Code.
Design:
1. Databricks writes all curated Delta tables to ADLS Gen2 (the system of record).
2. Fabric Lakehouse creates OneLake SHORTCUTS to those folders — no copy.
3. Power BI builds Direct Lake models on the shortcuts.
4. For sources that are NOT already Delta-on-ADLS (e.g. an operational
Azure SQL DB), use Fabric MIRRORING to replicate into OneLake as Delta.
-- After shortcuts exist, BI queries read the single physical copy:
SELECT c.region, SUM(f.amount) AS revenue
FROM fact_sales AS f -- shortcut to Databricks Delta
JOIN dim_customer AS c -- shortcut to Databricks Delta
ON f.customer_id = c.customer_id
GROUP BY c.region;
Step-by-step trace.
| table | source | how it reaches OneLake | copies |
|---|---|---|---|
fact_sales |
Databricks Delta on ADLS | shortcut (pointer) | 0 |
dim_customer |
Databricks Delta on ADLS | shortcut (pointer) | 0 |
orders_oltp |
Azure SQL Database | mirroring → Delta | 1 (managed) |
- Curated Delta tables already on ADLS Gen2 are exposed via shortcuts, so BI reads the exact bytes Databricks wrote — zero duplication, always current.
- The join runs in Fabric over those shortcuts, so Power BI and Databricks share one physical
fact_salesand onedim_customer. - Operational sources that are not Delta-on-ADLS cannot be pointed at directly, so mirroring replicates them into OneLake as Delta — one managed copy, kept near-real-time.
- The accepted trade-off: shortcuts add a small read-time indirection and depend on source availability, and mirrored sources cost one managed copy — cheaper and less drift-prone than copying everything nightly.
Output:
| design | physical copies of curated data | drift risk |
|---|---|---|
| nightly copy-everything | 2 (Databricks + OneLake) | high (refresh lag) |
| shortcuts + selective mirroring | 1 (+ managed mirrors for OLTP) | low |
Why this works — concept by concept:
- Shortcut virtualization — pointing at the existing Delta folder removes the second copy entirely, so there is nothing to drift out of sync.
- System of record — designating the Databricks lake as the source of truth means BI reads derive from one authoritative copy, not a stale duplicate.
- Mirroring for non-Delta sources — when a source cannot be pointed at, a managed near-real-time replica is the right, bounded exception rather than a fleet of copy jobs.
- One-copy principle — the whole OneLake design optimizes for ingest-once/read-everywhere; shortcuts are how you honor it across two products.
- Cost — storage drops from O(2 × curated) to O(1 × curated) plus O(mirrored OLTP), and you delete a nightly pipeline whose cost was O(all tables) every run.
ETL
Topic — etl
Copy-avoidance and ingestion-design problems
5. Choosing between them — cost & fit
DBU-plus-VM versus fixed capacity is the cost fork — and the right answer follows team, BI gravity, and scale
The decision usually comes down to two things an interviewer will push on: how each product bills, and which workloads each fits. Say the billing difference in one breath: Databricks meters consumption as DBUs on top of cloud VMs, while Fabric sells a fixed capacity in Capacity Units that every workload shares.
How Databricks bills.
- DBU + VM, two line items. You pay a DBU rate (a function of workload type — jobs vs all-purpose vs SQL — and tier) multiplied by runtime, plus the underlying Azure VM cost for the cluster. Faster engines like Photon can lower total cost by finishing sooner even at a higher DBU rate.
- Elastic and per-workload. Clusters scale up and down and job clusters disappear after a run, so spend tracks actual work; you can also run serverless and let Databricks manage the fleet.
- You own the tuning. Right-sizing clusters, autoscaling bounds, and Photon are levers that directly move the bill.
How Fabric bills.
- One capacity, measured in CU. You buy an F-SKU (F2, F4, … up to F2048); the number is the Capacity Unit budget shared by Spark, Warehouse, pipelines, and Power BI.
- Smoothing and bursting. Fabric smooths capacity usage over time and lets a job burst above the steady rate briefly, so short spikes do not require a bigger SKU; sustained overuse leads to throttling.
- The F64 threshold. F64 (and above) includes Power BI content consumption for users without separate Power BI Pro licenses — a real cost cliff that often drives the SKU choice for BI-heavy orgs.
- Predictable, not elastic. You pay for the capacity whether or not it is busy (unless you pause it), which is simpler to budget but less granular than per-job metering.
When Databricks wins.
- Large-scale data engineering and ML. Heavy Spark, streaming, and mature MLOps favor the engine you can tune.
- Code-first teams and multi-cloud. Repo-versioned pipelines, fine-grained cluster control, and running the same platform on AWS/GCP.
- Performance-critical reads. Photon, ZORDER, and cluster tuning give levers Fabric intentionally hides.
When Fabric wins.
- Power BI gravity. If BI is the center of gravity, Direct Lake over OneLake is hard to beat and the licensing at F64+ can be decisive.
- Low-code and mixed skill. Dataflows Gen2 and pipelines let analysts contribute without Spark; one SaaS surface reduces ops.
- Unified, predictable billing. One capacity across ingest, transform, warehouse, and BI is simpler to govern and budget.
Worked example — estimating the cheaper platform for a workload
Detailed explanation. The interview-friendly way to reason about cost is not to quote list prices but to model shape. A spiky nightly batch that is idle most of the day fits elastic DBU billing; a steady all-day mix of ETL plus heavy Power BI fits a fixed capacity. Model the shape, then the billing unit almost picks itself.
Question. Team A runs one heavy 2-hour Spark batch nightly and nothing else. Team B runs steady all-day ETL plus 300 Power BI users. Which billing model fits each, and why?
Input.
| team | workload shape | BI load |
|---|---|---|
| A | 2 h/night Spark, idle otherwise | none |
| B | steady all-day ETL | 300 Power BI users |
Code.
Heuristic:
spiky + idle-most-of-the-day -> elastic per-consumption (Databricks DBU;
job cluster runs 2 h then tears down)
steady + BI-heavy -> fixed shared capacity (Fabric F-SKU;
F64+ covers Power BI viewing licenses)
Step-by-step explanation. Team A's cluster only exists for two hours a night, so a job cluster billed in DBUs plus VM time is paid for ~2 hours, not 24 — elastic metering wins for spiky, idle-heavy work. Team B keeps a capacity busy all day and has 300 BI consumers; a single Fabric capacity at F64 or above covers both the compute and the Power BI viewing licenses under one predictable bill, which is cheaper and simpler than licensing 300 users separately on top of per-job compute.
Output.
| team | fits | reason |
|---|---|---|
| A | Databricks DBU (job cluster) | pay for 2 h, not idle time |
| B | Fabric capacity (F64+) | steady use + BI licensing under one SKU |
Rule of thumb. Elastic, spiky, engineer-tuned work leans Databricks; steady, BI-anchored, mixed-skill work leans Fabric — match the billing unit to the workload shape, not to the brand you like.
Azure lakehouse interview question on the cost model trade-off
Question. A team wants "cheap and predictable" but also runs an occasional huge ad-hoc Spark job. On a fixed Fabric capacity, what happens during that spike, and how would you decide between raising the SKU and offloading the job to Databricks?
Solution Using capacity smoothing, bursting, and a Databricks offload
Code.
Decision procedure:
1. Size the Fabric F-SKU for the STEADY workload (ETL + BI), not the peak.
2. Let bursting + smoothing absorb short spikes above the steady rate.
3. If the ad-hoc job is rare and short -> tolerate the burst (smoothed).
4. If it is large and sustained -> it will THROTTLE the capacity,
starving BI; offload it to a Databricks job cluster (elastic DBU)
that reads the SAME OneLake/ADLS Delta via a path or shortcut.
-- The offloaded Databricks job reads the very same Delta table Fabric uses,
-- so there is still ONE copy — only the compute moved off the capacity.
SELECT customer_id, COUNT(*) AS events
FROM delta.`abfss://data@lake.dfs.core.windows.net/fact_events`
GROUP BY customer_id;
Step-by-step trace.
| spike type | on fixed capacity | best action |
|---|---|---|
| short, rare | absorbed by burst + smoothing | keep on Fabric |
| large, sustained | throttles → BI slows | offload to Databricks DBU |
| grows permanently | chronic throttling | raise the F-SKU |
- Sizing the capacity for the steady state keeps the base bill predictable, which is the "cheap and predictable" the team asked for.
- Bursting lets a short spike temporarily exceed the steady CU rate, and smoothing spreads that cost over the following window, so rare spikes do not force a bigger SKU.
- A large, sustained job exceeds what bursting can absorb, so the capacity throttles — and because the capacity is shared, throttling starves the 300 BI users, the exact thing you must protect.
- The offload sends that one heavy job to an elastic Databricks job cluster billed in DBUs; it reads the same OneLake/ADLS Delta, so there is still one copy and BI on the capacity stays fast.
Output:
| lever | protects | cost behavior |
|---|---|---|
| burst + smoothing | short spikes | no SKU change |
| Databricks offload | BI on the capacity | pay DBUs only for the job |
| raise F-SKU | chronic higher baseline | higher fixed bill |
Why this works — concept by concept:
- Size for steady, not peak — provisioning to the baseline keeps the fixed bill low and uses bursting for the rare excursions instead of paying for peak all month.
- Smoothing and bursting — Fabric's capacity model is designed to absorb short spikes, so you do not over-provision for a once-a-week job.
- Throttling is shared pain — because one capacity backs BI and compute, a runaway job degrades reports; protecting the capacity is protecting the business users.
- Elastic offload — moving the heavy, spiky job to per-consumption DBU billing matches its shape to the right cost model while preserving the one-copy lake.
- Cost — steady spend stays O(baseline capacity); the spike cost becomes O(job runtime) on Databricks instead of forcing an O(peak) capacity all month.
Optimization
Topic — optimization
Capacity-planning and cost-tuning problems
Cheat sheet — Azure lakehouse recipes
Delta upsert (Databricks or Fabric Spark).
MERGE INTO customers t USING updates s
ON t.customer_id = s.customer_id
WHEN MATCHED THEN UPDATE SET t.tier = s.tier
WHEN NOT MATCHED THEN INSERT (customer_id, tier) VALUES (s.customer_id, s.tier);
Compact + cluster for faster reads (Databricks).
OPTIMIZE events WHERE event_date >= '2026-01-01' ZORDER BY (customer_id);
Unity Catalog grant (Databricks).
GRANT SELECT ON TABLE main.sales.fact_sales TO `analysts`;
Create a OneLake shortcut (Fabric, external ADLS Gen2).
{"name": "dim_customer",
"target": {"adlsGen2": {"location": "https://lake.dfs.core.windows.net/curated",
"subpath": "/dim_customer"}}}
Fabric Warehouse table with CTAS (T-SQL).
CREATE TABLE daily_revenue AS
SELECT sale_date, SUM(amount) AS revenue FROM sales GROUP BY sale_date;
Direct Lake note (Fabric).
Build the semantic model on OneLake Delta tables and keep storage mode =
Direct Lake (not Import, not DirectQuery) for fast, always-current Power BI.
Feature comparison.
| Concern | Azure Databricks | Microsoft Fabric |
|---|---|---|
| Compute control | you size Spark / Photon clusters | Microsoft runs it; you buy capacity |
| Storage format | Delta Lake on ADLS Gen2 | Delta Parquet in OneLake (ADLS Gen2) |
| Governance | Unity Catalog (catalog.schema.table) |
workspaces + OneLake + Entra ID |
| BI acceleration | DirectQuery / import to SQL warehouse | Direct Lake over OneLake |
| Billing unit | DBU × runtime + cloud VM | capacity Units (F2–F2048), smoothed |
| Best fit | code-first DE / ML at scale | Power BI gravity, low-code, one SaaS |
Frequently asked questions
What is the difference between Azure Databricks and Microsoft Fabric?
Azure Databricks is an engineer-controlled lakehouse platform: you operate Apache Spark clusters, tune Photon, manage Delta Lake tables, and govern them with Unity Catalog. Microsoft Fabric is an integrated SaaS analytics platform where Microsoft runs the engines and you consume outcomes over one capacity, with OneLake as the shared lake and Power BI built in. The core distinction is control versus integration — both write the same Delta Parquet on ADLS Gen2, so the difference is the control plane, not the storage.
Do Databricks and Fabric use the same storage?
Effectively yes. Databricks writes Delta Lake tables to Azure Data Lake Storage Gen2, and OneLake is itself an ADLS Gen2 endpoint that stores tables as Delta Parquet. Because both persist the same open format, a table written by one can be read by the other through a OneLake shortcut with no copy or conversion, which is the foundation of running the two products together.
What is Direct Lake in Microsoft Fabric?
Direct Lake is a Power BI storage mode that reads Delta Parquet directly from OneLake, paging the needed columns into the analytics engine's memory on demand. It gives import-like query speed without a scheduled refresh and without translating queries to a remote source like DirectQuery, so reports are both fast and always current. If a query hits an unsupported feature, Direct Lake transparently falls back to DirectQuery to keep results correct.
How does Fabric capacity pricing compare to Databricks DBUs?
Databricks bills a DBU rate multiplied by runtime plus the underlying cloud VM cost, so spend is elastic and tracks actual work — good for spiky, idle-heavy pipelines. Fabric bills a fixed capacity measured in Capacity Units (F2 through F2048) shared by all workloads, with smoothing and bursting to absorb short spikes and throttling when overused. Fabric is more predictable and simpler to budget, while Databricks is more granular and tunable per job; the F64 threshold, which bundles Power BI viewing licenses, often decides the SKU for BI-heavy orgs.
Can Fabric read Databricks Unity Catalog tables?
Yes. A Fabric OneLake shortcut can point at the ADLS Gen2 location of a Databricks/Unity Catalog Delta table and surface it in a Lakehouse without copying, and Fabric mirroring can replicate an external database or catalog into OneLake as Delta when a live pointer is not enough. Because both speak Delta on ADLS Gen2, the interop is a virtualized pointer rather than an ETL copy, and permissions are still enforced on both sides.
When should I choose Databricks over Fabric?
Choose Databricks when you have code-first data engineering or ML at scale, need Spark and Photon tuning, run heavy streaming, or want the same platform across multiple clouds — cases where engineer control of compute is the value. Choose Fabric when Power BI is your center of gravity, your team spans low-code and pro-code skills, or you want one predictable SaaS bill across ingest, warehouse, and BI. Many organizations run both, using OneLake shortcuts so the two share a single physical copy of the data.
Practice on PipeCode
Pipecode.ai is Leetcode for Data Engineering — every idea above, from the Delta MERGE and ZORDER tuning to Direct Lake semantic models and OneLake shortcut design, maps to a hands-on practice room where you build the solution against real graded inputs. PipeCode pairs each reading with 450+ DE-focused problems and a real-time scoring engine, so your answer to "Databricks or Fabric for this workload?" holds up under a senior interviewer's depth probes.
Practice data-warehouse problems now →
Optimization drills →





Top comments (0)