Engine Architecture & Storage Internals
How a relational engine is actually built: connections come in, pages and the buffer pool sit in the middle, and write-ahead logging plus recovery guarantee durability underneath. Interviewers probe these internals to see whether you understand what the database does with your SQL beyond the syntax — why commits are durable, where memory goes, and what happens after a crash.
part ofRelational database conceptsoverview, primer and where to startread it →on this pageshowhide
explore
- Client/Server Model & Connection Handling4 questions
- Connection Pooling4 questions
- Background Workers4 questions
- Pages, Heap Files & Row Layout6 questions
- Buffer Pool & Eviction5 questions
- Write-Ahead Logging (Redo/Undo)5 questions
- Checkpoints5 questions
- Crash Recovery (ARIES Concept)5 questions
- Dead Version Cleanup (Vacuum/Purge)5 questions
- Row Store vs Column Store3 questions
- Memory Areas & Spill-to-Disk3 questions
- System Catalogs5 questions
- PostgreSQL DBAroleanchors this topic
- AI & Data Scientistrole
- AI Engineerrole
- Backend Developerrole
- Computer Scienceskill
- Cyber Security Expertrole
- Data Analystrole
- Data Engineerrole
- Forward Deployed Engineerrole
- Full Stack Developerrole
- Java Backend Developerrole
- Kotlin Backend Developerrole
- MLOps Engineerrole
- Machine Learning Engineerrole
- Server-Side Game Developerrole
- Software Architectrole
questions
page 2 of 2Columnar storage usually compresses far better than row storage. Explain why, describe run-length encoding and dictionary encoding, and say how compression affects query execution beyond saving disk space.
basics
~20 sA column block holds one data type with similar, often repeating values, so it compresses far better than a row block that interleaves types. Run-length encoding stores value plus repeat count; dictionary encoding replaces values with small codes into a value table. Beyond disk savings, scans read fewer bytes and engines can filter and aggregate on encoded data without decompressing.
Explain how a database sorts a result set far larger than the memory budget given to the sort operation, and describe the I/O cost of that algorithm.
basics
~20 sIt uses an external merge sort: fill memory, sort that chunk, write it out as a sorted run, repeat until input is exhausted, then merge the runs by repeatedly taking the smallest head value across them. Each pass reads and writes the whole dataset, and more memory means fewer, larger runs and usually a single merge pass.
The SQL-standard INFORMATION_SCHEMA views and an engine's native catalog (for example a pg_catalog-style set of system tables, or sys.* / DBA_* dictionary views) both describe the same database. How do they differ, and when would you choose each?
basics
~20 sINFORMATION_SCHEMA is a standard, portable, read-only view layer with the same column names across engines, but only standard concepts. The native catalog is the real underlying dictionary: engine-specific, far richer, usually faster. Use the standard for portable tooling, native for depth and performance.
How would you use a database's catalog metadata to answer operational questions such as which indexes are never used, how much space a table and its indexes occupy, and whether the optimizer's statistics are stale?
basics
~20 sJoin the engine's native catalog: object tables for names and ownership, size functions or storage columns for bytes, index-usage counters for scans since reset, and statistics catalogs for row estimates, distinct values and the last analyze time. The standard views cannot answer any of these.
What do a database's automatic statistics and vacuum/purge maintenance daemons do for you, and what symptoms appear when they cannot keep up with the write rate?
basics
~20 sThey refresh optimizer statistics and reclaim space from dead row versions, on thresholds and under a throttle. Falling behind shows up as table and index bloat, growing history/undo, degrading scans, sudden bad plans from stale statistics, and maintenance that never finishes on the hottest tables.
Your monitoring shows the database's buffer cache hit ratio steady at 99.5%, yet query latency has doubled. Explain how a high hit ratio can coexist with a serious performance problem, and what you would measure instead.
basics
~20 sHit ratio is a ratio of page accesses, not of work. A query doing a hundred times more page accesses than needed can keep the ratio high while burning CPU and time. Measure absolute logical reads per query, physical reads, and latency - not the ratio.
A nightly reporting job scans a table far larger than the server's memory, and for a while afterwards the normal transactional workload runs much slower. Explain the effect this has on the engine's page cache and what mechanisms engines use to prevent it.
basics
~20 sThe scan reads pages used once and lets them displace the hot working set - cache pollution. The OLTP workload then misses on pages it used to hit until the pool refills. Engines defend with midpoint insertion, small ring buffers for bulk reads, and marking scan pages for immediate reuse.
Every few minutes a production database shows a burst of write I/O with latency spikes across unrelated queries, and the bursts line up with its checkpoints. Explain the mechanism and how you would smooth it out.
basics
~20 sDirty pages accumulate between checkpoints and are then flushed in a burst of random writes that saturates the device, so every query queues behind it. Smooth it by spreading the flush over most of the interval, letting a background writer trickle pages out continuously, and reducing dirty-page accumulation.
A connection pooler can hand a server connection to a client for the duration of a whole session or only for the duration of a transaction. Compare these two pooling modes and explain what stops working in the transaction-scoped one.
basics
~20 sSession pooling binds a server connection to a client for its whole session - safe, but the multiplexing ratio is poor. Transaction pooling returns the server connection after each commit or rollback, allowing far more clients per server connection, but anything session-scoped breaks: session settings, temporary tables, session-level prepared statements, advisory locks, and cursors held across transactions.
When a relational engine rolls back a transaction, the undo work itself is written to the transaction log as compensation log records. What problem do those records solve, and what happens if the server crashes again while a rollback is still in progress?
basics
~20 sA compensation log record (CLR) logs each reversal as it is performed and carries a pointer to the next record still to be undone. That makes rollback restartable and never repeated: after a second crash, recovery reads the CLRs, sees which reversals are done, and resumes from the pointer. CLRs are redo-only and are never themselves undone.
In ARIES-style recovery, the redo pass reapplies changes made by transactions that were still uncommitted at crash time, only for the undo pass to roll them back immediately afterwards. Why is that apparently wasteful design chosen over skipping the uncommitted transactions during redo?
basics
~20 sRedo repeats history so that after it, the pages match the exact state at the moment of the crash. Undo then operates on a state it understands, using the same rollback path used at runtime. Selective redo would create a state that never existed, where logged before-images and page-internal structures no longer line up.
When a stored row is rewritten at a larger size and no longer fits on its current page, what options does the storage engine have, and how does it find a page with enough free space for a new row in the first place?
basics
~30 sFor a new row the engine consults a free-space map, a compact per-page summary of remaining space, to pick a page without scanning the file. If a rewritten row no longer fits, the engine first compacts the page; if that is still not enough it places the row on another page, either updating index entries or leaving a forwarding pointer behind, which costs an extra read on later lookups.
Compare storing table rows in an unordered heap file, with secondary structures pointing into it, against storing the rows inside the primary-key structure itself (an index-organized or clustered table). What are the tradeoffs?
basics
~20 sA heap appends rows wherever there is space, so inserts are cheap and every lookup costs an index probe plus a fetch into the heap. An index-organized table keeps rows sorted inside the primary-key structure, so primary-key lookups and ranges need no extra fetch, but secondary lookups go through the primary key and inserts in random key order cause page splits and reordering.
A hash join's build-side hash table does not fit in the memory budget for that operator. Explain what the engine does instead, and what goes wrong when the join key is heavily skewed.
basics
~20 sIt partitions both inputs by a hash of the join key into batches written to temporary files, then joins one pair of matching partitions at a time in memory. If one key value dominates, its partition stays too big to fit, so partitioning recurses without helping and that batch degrades badly.
When a session executes DDL such as adding a column to a busy table, what happens to the engine's catalog rows and to the in-memory catalog caches that other sessions hold? Why can concurrent sessions block, and why might a session briefly act on stale metadata?
basics
~20 sDDL updates catalog rows under a lock on the object. Because every backend caches catalog entries and compiled plans, the change must be broadcast as an invalidation; other sessions block on the lock or on reaching a safe point, then rebuild their cached definitions and replan. Long-running readers delay the whole thing.
What is table and index bloat in an MVCC database, what symptoms does it produce, and what actually returns the space — to the object for reuse versus to the operating system?
basics
~20 sBloat is space allocated to dead versions and half-empty pages rather than live data. Symptoms: files far larger than live data, scans reading mostly garbage, cache polluted, plans degrading. Ordinary cleanup frees space for reuse inside the object; only a rewrite or dropping a partition returns it to the operating system.
Committing a transaction usually requires flushing the write-ahead log to stable storage with an fsync-style call. How does that shape commit latency and throughput, and what does group commit do about it?
basics
~20 sCommit latency is floored by the storage device's flush latency, since the commit record must be durable before acknowledgement. Group commit batches many concurrent commits into one flush, so throughput scales with concurrency even though single-commit latency does not improve.
Log records in a write-ahead log are stamped with a monotonically increasing log sequence number, and data pages carry one too. What is an LSN used for?
basics
~20 sAn LSN is a monotonically increasing position in the log. Each page stores the LSN of the last change applied to it, so the engine can enforce log-before-data, skip redo of changes a page already has, and address a point in the log stream.
The directory holding a database's write-ahead log segments keeps growing until the disk is nearly full, even though the database's data size is stable. What causes log segments to accumulate, and how do you reason about it?
basics
~20 sLog segments are recycled only once nothing still needs them. Something is holding a required position: an unfinished checkpoint, a long-running transaction, a lagging or disconnected replica, a failing archive process, or a stalled backup. Find the oldest required log position and its owner.
How would you decide how much memory to give a database's buffer pool on a dedicated 128 GB server, and what is 'double buffering' between the engine's page cache and the operating system's page cache?
basics
~20 sSize it from the working set, not a fixed percentage, and leave room for per-connection memory, sort/hash workspace and the OS. Double buffering is the same page being cached twice - once by the engine, once by the kernel - wasting RAM; direct I/O or a much larger pool avoids it.
How would you choose a checkpoint interval or recovery-time target for a production database, and what are you trading off in each direction?
basics
~20 sStart from the recovery-time objective, since the interval bounds how much log replay a crash costs, then check the steady-state price: shorter intervals mean more repeated page writes and more full-page-image log volume. Choose the longest interval that still meets the recovery target.
A transactional database is being slowed by long analytical scans from a BI tool. Discuss the architectural options for serving both transactional and analytical workloads, including hybrid designs that maintain row and column copies of the same data, and the tradeoffs you would weigh.
basics
~20 sOptions: keep one row store and accept the scan cost; offload analytics to a replica; copy data into a columnar analytical system; or use a hybrid engine that keeps a columnar representation alongside the row data, updated from the transaction stream. Trade freshness, storage and operational cost against isolation of the two workloads.
You own a queue-like table in an MVCC database where rows are inserted and then updated to a completed state thousands of times per second, and background cleanup can never keep up. How would you redesign around dead-version accumulation?
basics
~20 sReduce versions produced and make removal a metadata operation. Narrow the churned row, cut updates per item, partition by time or state so completed work is dropped as a partition rather than deleted, tune cleanup to be far more aggressive on that table, and keep transactions short so the horizon never stalls.
You are designing a multi-tenant product where each tenant could get its own schema, potentially tens of thousands of schemas and millions of catalog rows. What are the catalog-level consequences, and how would you decide between schema-per-tenant and one shared schema with a tenant identifier column?
basics
~20 sEvery schema multiplies catalog rows for tables, columns, indexes and constraints. At tens of thousands of tenants the dictionary itself becomes a hot, large, contended structure: slower planning, slower introspection, heavier backup and migrations that must run N times. Shared-schema scales the catalog; schema-per-tenant buys isolation.
showing 31–54 of 54