In a Hudi Merge-on-Read table, how do snapshot and read-optimized queries differ?
answer
- one view pays at query time, one does not
- freshness is bounded by the last compaction
- deleted rows can reappear in one of them
- Hive sync gives you two table names
- the suffixes are _rt and _ro
basics
~20 sA snapshot query merges each file slice's base file with its log files at read time, so it returns the latest committed state. A read-optimized query reads base files only, so it is faster but shows data as of the last compaction.
solid answer
~40 sA Merge-on-Read file slice is a Parquet base file plus any log files appended since it was written. The **snapshot** query type reads both and merges them by record key on the fly: it is fully fresh, including deletes, but pays CPU and memory per query in proportion to how much unmerged log data has piled up. The **read-optimized** query type skips the logs entirely and scans base files only, giving plain-Parquet performance but returning the table as of the last successful compaction — so recent updates are missing and recently deleted rows can still appear. Hive sync exposes both as separate tables, `<name>_rt` for the snapshot view and `<name>_ro` for the read-optimized one. On a Copy-on-Write table the distinction is meaningless, because there are never any logs to merge.
code
sql · 3 lines-- Hive sync registers two tables for one Merge-on-Read table
SELECT count(*) FROM orders_rt; -- snapshot: base files merged with log files
SELECT count(*) FROM orders_ro; -- read-optimized: base files onlygo deeper
Recall that one view merges logs into the base file and one does not, and that skipping the merge trades freshness for speed. Know that only Merge-on-Read tables have the distinction.
Explain what a file slice contains and why the read-optimized result is pinned to the last compaction rather than to a chosen timestamp. Name the _rt and _ro Hive-synced tables.
Be ready to route workloads between the two views, explain the surviving-deleted-row failure to a stakeholder, and use the read-optimized view as an emergency lever while compaction is repaired.
Own freshness as a published contract: which consumers may use the read-optimized view, what staleness bound compaction guarantees, and whether your engine fleet supports the snapshot view at all before standardizing on Merge-on-Read.
## What a file slice contains In an Apache Hudi `MERGE_ON_READ` table, records in a partition are organized into **file groups** identified by a file ID. Each version of a group is a **file slice**: one Parquet **base file** plus zero or more **log files** holding blocks appended since that base file was written. Ingestion never rewrites the base file — it appends log blocks and records a `deltacommit` — so at any moment a slice can hold committed changes that are not yet inside its Parquet file. Everything about the two query types follows from that. ## Snapshot queries A snapshot query returns the table as of the latest committed instant, which is what a SQL user normally expects. To do that it must open each relevant file slice, read the base file, replay every log block on top, and resolve conflicts by record key using the precombine field. Delete blocks remove rows from the result. What comes out is correct and fresh, including deletes issued seconds ago. The cost is real work per query: the reader materializes a merged view in memory, and both CPU time and memory grow with the number and size of log files on each slice. A table whose compaction has fallen behind can make the same dashboard query take several times longer than it did the previous day, without any change to the query or the data volume. ## Read-optimized queries A read-optimized query deliberately ignores the log files. It scans only the base Parquet files of the current file slices, which means the engine does exactly what it would do on a plain Parquet dataset: column pruning, predicate pushdown, vectorized reads, nothing else. Performance is essentially Copy-on-Write performance. The tradeoff is staleness with a very specific meaning: the result reflects the table **as of the last completed compaction** on each file group, not as of a wall-clock time you chose. Updates that arrived after compaction are missing, and rows deleted after compaction still appear, because the delete lives only in a log block the query is not reading. That last point traps people: it looks like a correctness bug in the table, and it is actually the documented behaviour of the query type. ## How engines expose the two views When Hudi syncs a Merge-on-Read table to a Hive metastore, it registers two table names: `<name>_rt` for the real-time (snapshot) view and `<name>_ro` for the read-optimized view. Both point at the same underlying data; they differ only in which reader is used. Spark's Hudi datasource selects the view through a query-type option instead. Engine support varies, and some engines historically exposed only the read-optimized view of a Merge-on-Read table — so "which views does this engine actually support" is a question worth answering before you commit a platform to Merge-on-Read. ## The third query type Hudi also offers **incremental** queries, which return only the records changed between two instants on the timeline rather than a full table state. That is a different axis from the snapshot/read-optimized freshness tradeoff and belongs with the timeline and indexing material; mention it as a third option and move on. ## Copy-on-Write collapses the distinction In a `COPY_ON_WRITE` table, every file slice is just a base file — updates were merged in at write time. There are no logs, so the snapshot view and the read-optimized view return exactly the same rows, and asking for the read-optimized view buys nothing. This is a useful sanity check in an interview: if someone claims read-optimized queries speed up a Copy-on-Write table, they have not understood where the merge cost comes from. ## Using the choice in practice A sensible pattern is to route by workload. Interactive dashboards, BI extracts and large scans that tolerate compaction-interval staleness use the read-optimized view and get predictable latency. Operational lookups, correctness-critical reconciliation and anything that must reflect a delete immediately use the snapshot view. Make the staleness explicit: if compaction runs after every few delta commits, read-optimized staleness is bounded by that interval, and you can publish it as an SLA. If compaction is unmonitored, the read-optimized view silently drifts arbitrarily far behind — which is why the two topics, query type and compaction health, are always discussed together. A final operational note: the read-optimized view is also the emergency lever. When snapshot queries degrade because logs have accumulated, pointing heavy readers at `_ro` restores their latency immediately while you fix compaction — at the cost of freshness, and with the deleted-rows caveat clearly communicated to whoever reads the result.
- Why can a read-optimized query on a Merge-on-Read table return a row that was deleted an hour ago?Because the delete was written as a delete block in a log file, and the read-optimized view reads base files only. The row is still physically present in the Parquet base file and will remain visible until compaction rewrites that file slice. Only the snapshot view replays the log and drops the row.
- Do these two query types mean anything on a Copy-on-Write table?No. In Copy-on-Write, updates are merged into a new base file at write time and there are never log files, so a file slice is just a Parquet file. The snapshot and read-optimized views return identical rows, and choosing read-optimized buys no performance.
- How would you bound the staleness a read-optimized consumer sees?Bound it by the compaction interval and monitor it. Schedule compaction after a fixed number of delta commits or on a time trigger, alert when the newest completed compaction instant falls behind that target, and publish the resulting worst-case lag as the freshness SLA for the read-optimized view.
saying these in an interview costs you the question
- Says read-optimized queries return older data you can choose a time for
- Claims read-optimized skips deletes correctly, only missing updates
- Thinks read-optimized speeds up a Copy-on-Write table too
- Confuses read-optimized with the incremental query type
- Believes snapshot queries read log files instead of the base file