Prepare for DBMS interview questions grouped by experience level.
0-2 Years
A Database Management System is software that actually manages storing, retrieving, and organizing data efficiently. It solves problems flat files genuinely struggle with, like data redundancy, inconsistent updates across duplicate copies, and having genuinely no built-in way to enforce data integrity or handle multiple users accessing the exact same data at once.
A database is the actual, genuine collection of organized data itself. A DBMS is the software that actually manages that database, providing the tools to create, query, update, and secure the data, rather than requiring an application to genuinely manage all of that low-level detail directly on its own.
Relational (RDBMS), organizing data into genuinely related tables, like MySQL or PostgreSQL. NoSQL, covering document stores, key-value stores, and graph databases, genuinely built for more flexible or specialized data models. Hierarchical and network databases are genuinely older models, largely superseded by the relational model in most modern use.
Reduced data redundancy, since related data is genuinely organized and shared rather than duplicated across separate files. Built-in data integrity through constraints. Concurrent access control, letting multiple users genuinely work with the data at the same time safely. And built-in backup and recovery capability that a plain file system genuinely doesn't provide on its own.
Data independence means the way data is actually stored physically can genuinely change without requiring a change to how an application logically accesses it. Logical data independence protects the logical schema from a change in the conceptual schema, and physical data independence protects the conceptual schema from a change in the actual physical storage.
A schema is the actual, overall structure or design of a database, its tables, columns, and relationships, genuinely defined once and rarely changed. An instance is the actual data genuinely stored in the database at a specific given moment, which changes constantly as records are actually inserted, updated, and deleted.
The ER model represents a database's design conceptually, using entities (real-world objects), attributes (their properties), and relationships (how entities genuinely connect to each other). It's used early in database design to actually plan a database's structure before it's genuinely translated into actual tables.
An entity is a genuinely distinct real-world object or concept, like a Student or a Course. An attribute is a genuinely specific property describing that entity, like a Student's name or date of birth. An entity genuinely has several attributes describing it.
One-to-one, where one entity instance genuinely relates to exactly one instance of another. One-to-many, where one entity instance genuinely relates to several instances of another. Many-to-many, where several instances of each entity genuinely relate to several instances of the other.
A weak entity genuinely can't be uniquely identified by its own attributes alone, and depends on a genuine relationship with another entity, called its owner, for its actual identification. A strong entity genuinely has its own sufficient attributes, typically a primary key, to be uniquely identified entirely on its own.
The relational model represents data as a genuine collection of tables (relations), each row being a genuine record and each column an attribute. The ER model is a genuinely conceptual design tool used earlier, and it's typically translated into the relational model's actual tables during the genuine database design process.
Each entity genuinely becomes its own table, with its attributes becoming genuine columns. A one-to-many relationship is genuinely implemented by adding a foreign key to the table on the many side. A many-to-many relationship genuinely requires an additional junction (or bridge) table connecting the two related entities together.
A primary key uniquely identifies each row in a table. It enforces that its value must genuinely be unique across every row and can never genuinely be NULL. A table can have only one primary key, though that key can genuinely span more than one column if needed.
A candidate key is any column, or combination of columns, that could legitimately serve as a table's unique identifier. A table can genuinely have several candidate keys, and exactly one of them is actually chosen to become the primary key, while the others remain genuinely valid, unused alternatives.
A foreign key is a column (or set of columns) in one table that references the primary key of another table, establishing and enforcing a genuine relationship between them. It solves the problem of referential integrity, preventing you from inserting, for instance, an order that genuinely references a customer ID that doesn't actually exist.
A super key is any genuine combination of columns that uniquely identifies a row, even if it includes genuinely unnecessary extra columns beyond what's actually needed. A candidate key is a genuinely minimal super key, containing no unnecessary extra column that could actually be removed while still keeping uniqueness intact.
A composite key is a primary key made up of two or more columns combined together, where the combination of those column values is genuinely unique even if no single column among them is unique on its own. A common example is a table tracking enrollments, where the combination of student_id and course_id together genuinely forms the composite key.
Referential integrity ensures a foreign key value in one table genuinely always corresponds to an actual, existing primary key value in the referenced table, never pointing to something that doesn't actually exist. It's genuinely enforced by the DBMS itself through foreign key constraints defined when the tables are actually created.
Normalization organizes a database's tables to genuinely reduce data redundancy and prevent certain update anomalies, splitting data into multiple related tables rather than storing everything redundantly in one large, flat table. It's done to keep data consistent, since a value stored in exactly one place only ever genuinely needs to be updated in that one place.
1NF requires every column to genuinely hold a single, atomic value, with no repeating groups or genuinely embedded lists within one field, and every row must genuinely be uniquely identifiable.
2NF requires a table to genuinely already be in 1NF, and additionally requires every non-key column to depend on the entire primary key rather than only part of it, which is genuinely only relevant for a table with a composite primary key. It addresses a partial dependency, where a column genuinely depends on only part of that composite key.
3NF requires a table to genuinely already be in 2NF, and additionally requires every non-key column to depend only on the primary key, not on another non-key column. It addresses a transitive dependency, where a column genuinely depends indirectly on the primary key through another non-key column.
A table storing OrderID, CustomerID, and CustomerName together violates 3NF, since CustomerName genuinely depends on CustomerID, a non-key column, rather than directly on the primary key OrderID. Splitting CustomerName into a genuinely separate Customers table, referenced by CustomerID, resolves that transitive dependency.
An update anomaly happens when the same piece of data is genuinely duplicated across multiple rows, and updating it in one place but forgetting another leaves the data genuinely inconsistent. Normalization prevents this by ensuring each piece of data lives in genuinely exactly one place, so there's only ever one row to actually update.
Relational algebra is a genuinely formal set of operations for actually manipulating and querying relational data, forming the genuinely theoretical foundation SQL itself is actually built on. It's used to describe genuine query operations mathematically and precisely, rather than through SQL's own more genuinely English-like syntax.
Selection filters rows from a relation based on a given genuine condition, similar to a SQL WHERE clause, returning only the rows genuinely satisfying that condition.
Projection selects genuinely specific columns from a relation, discarding the rest, similar to specifying particular columns in a SQL SELECT statement rather than using *.
A natural join combines two relations based on their genuinely common attribute values, keeping only genuinely matching rows. A Cartesian product pairs every single row from one relation with genuinely every single row from the other, with no actual matching condition applied at all, producing a genuinely much larger result set.
Union requires the two relations to be genuinely union-compatible, meaning they must have the exact same number of columns, with genuinely corresponding columns sharing the same actual data type. Without that compatibility, combining the two relations genuinely wouldn't make logical sense.
A transaction groups one or more database operations together into a genuinely single, all-or-nothing unit of work. It guarantees that either every operation in the group genuinely succeeds together, or genuinely none of them take effect at all.
Atomicity guarantees a transaction is genuinely all-or-nothing. Consistency guarantees a transaction takes the database from one genuinely valid state to another, never violating a defined constraint. Isolation guarantees concurrent transactions don't genuinely interfere with each other unexpectedly. Durability guarantees that once a transaction genuinely commits, its changes survive even a subsequent system crash.
Active (currently executing), Partially Committed (finished its final operation but not yet actually committed), Committed (successfully completed and genuinely made permanent), Failed (an error genuinely occurred and it can't proceed), and Aborted (genuinely rolled back after failure).
COMMIT makes a transaction's changes genuinely permanent, actually saving them to the database. ROLLBACK undoes every genuine change made so far within the current transaction, reverting the database back to the state it was in before that transaction genuinely began.
A deadlock happens when two transactions are each genuinely waiting on a resource the other one currently holds, so neither transaction can ever actually complete. A genuinely common cause is two transactions acquiring locks on the same two rows, but in the opposite order from each other.
A money transfer genuinely involves two separate operations, debiting one account and crediting another. Without atomicity, a genuine system crash occurring between those two operations could leave money genuinely debited from one account without ever actually being credited to the other, an inconsistent state atomicity is specifically designed to genuinely prevent.
3-6 Years
BCNF is a genuinely stricter version of 3NF, requiring that for genuinely every functional dependency, the left-hand side must genuinely be a super key. A table can genuinely satisfy 3NF but still violate BCNF in certain genuinely specific cases involving overlapping candidate keys, which 3NF's own genuine rules don't fully address.
4NF addresses multi-valued dependencies, where one attribute genuinely, independently determines multiple values of another attribute, unrelated to any other genuine dependency in the table. It requires a table already genuinely in BCNF to also have genuinely no non-trivial multi-valued dependency.
Denormalization intentionally introduces some genuine redundancy back into a database design, often by duplicating data across tables, specifically to improve read performance by genuinely reducing the number of joins a common query needs. It's a deliberate trade-off, accepting more redundancy and more careful write logic for meaningfully faster reads.
A functional dependency means one attribute's value genuinely determines another attribute's value, written as A → B, meaning knowing A's value genuinely tells you B's value. Normalization rules are genuinely built directly around identifying and properly handling these functional dependencies to actually eliminate redundancy.
Weigh the actual, genuine benefit of reduced redundancy against the real cost of more joins genuinely needed to reconstruct data for common queries. A genuinely read-heavy reporting system might reasonably stay at a lower normal form (or be deliberately denormalized), while a genuinely write-heavy transactional system usually benefits more from higher, stricter normalization.
An index is a genuinely separate data structure, typically a B-tree, letting the database find rows matching a specific value quickly, without genuinely scanning every single row in the table one by one. It works much like a book's own index, letting you jump directly to a relevant page instead of reading the entire book.
A clustered index determines the genuinely actual physical order rows are stored on disk, so a table can genuinely have only one. A non-clustered index is a genuinely separate structure that points back to the actual row's location, and a table can genuinely have several of them.
A B-tree is a genuinely self-balancing tree structure keeping data sorted while supporting efficient search, insertion, and deletion, all in logarithmic time. It's genuinely common for database indexes because it keeps more keys per node than a plain binary tree, meaning fewer levels for the same number of keys, and genuinely fewer disk reads needed to traverse it.
A B-tree index keeps values genuinely sorted, supporting both exact matches and range queries efficiently. A hash index maps a value directly to a genuine location using a hash function, giving genuinely very fast exact-match lookups but no ability to efficiently support a range query at all.
Every index genuinely has to be updated whenever a row is inserted, updated, or deleted, so more indexes mean more genuine overhead on every single write operation. An index also genuinely consumes real storage space, so indexing every column just in case tends to genuinely slow down writes without a matching, real benefit.
Multiple transactions genuinely running at the same time against the exact same data can interfere with each other in a way that genuinely produces an incorrect, inconsistent result if left completely uncontrolled. Concurrency control mechanisms ensure that concurrent execution genuinely still produces a result equivalent to running those transactions one at a time, in some genuine order.
A lock restricts genuine access to a piece of data while a transaction is actually using it. A shared lock allows multiple transactions to genuinely read the same data simultaneously, but blocks writing. An exclusive lock allows only one genuine transaction to both read and write, blocking every other transaction from doing either.
Two-phase locking splits a transaction's own lock handling into a genuine growing phase, where it only acquires locks, and a shrinking phase, where it only releases them, never acquiring a genuinely new lock after releasing one. It guarantees the resulting schedule is genuinely serializable, meaning its result is equivalent to running transactions one at a time in some order.
Pessimistic concurrency control acquires a genuine lock upfront, before making a change, blocking any other transaction from touching that same data until the lock is released. Optimistic concurrency control assumes conflicts are genuinely rare, allows concurrent access without an upfront lock, and instead checks at the moment of actually committing whether the underlying data genuinely changed since it was first read.
Check the database's own genuine deadlock logs, which most database engines record automatically, showing exactly which two queries were genuinely involved and precisely what locks each one was actually waiting on. The typical fix is ensuring transactions across the whole application genuinely, consistently acquire locks on shared resources in the exact same order.
A schedule is the actual, genuine sequence in which the operations of multiple transactions are actually executed, potentially interleaved together. A serial schedule executes every genuine transaction's operations completely, one transaction fully finishing before the next genuinely begins, with no interleaving at all.
A serializable schedule, even though its operations are genuinely interleaved for better performance, produces the exact same actual result as some genuine serial (non-interleaved) execution of those same transactions would have. It matters because it lets a DBMS genuinely run transactions concurrently for better performance, while still guaranteeing genuinely correct, predictable results.
Conflict serializability checks whether a schedule can genuinely be transformed into a serial schedule by swapping only non-conflicting operations. View serializability is a genuinely broader, more permissive condition, checking whether transactions genuinely read and write the exact same final values as some serial schedule would, even if the underlying operations couldn't genuinely be swapped into that exact serial order.
A cascading rollback happens when one transaction's genuine failure and rollback forces another transaction, which had already read data written by the genuinely first, uncommitted transaction, to also be rolled back. It's undesirable because it can genuinely cascade through many transactions, wasting significant real work that would otherwise have been genuinely valid.
File organization describes how actual data records are physically arranged and stored on disk. It matters because the specific chosen arrangement genuinely affects how quickly the DBMS can actually locate, insert, and update records, since disk access itself remains genuinely one of the slower operations in the entire system.
In heap file organization, records are genuinely stored in no particular order, simply wherever space is actually available, which makes inserting a genuinely new record very fast. The trade-off is that searching for a specific record genuinely requires scanning through potentially the entire file, since there's no actual inherent ordering to exploit.
Records are genuinely stored in sorted order based on a specific key field. This genuinely benefits range queries and sequential access significantly, since related records sit physically genuinely close together, though inserting a genuinely new record can require shifting other records to actually maintain that sorted order.
A clustering index genuinely determines the actual physical order records are stored in on disk, based on a specific column's value. Since it directly genuinely dictates physical storage order, a table can genuinely have only one clustering index, unlike a non-clustering index, which a table can have several of.
6-8 Years
Log-based recovery records every genuine database change in a genuinely sequential log file before that change is actually applied to the real data files. It relies on the log because the log can genuinely be replayed or undone after a crash to actually restore a consistent state, something that would genuinely be far harder to reliably achieve by inspecting the actual data files alone.
WAL genuinely requires that a log record describing a change must actually be written to genuinely stable storage before the actual corresponding data change is written. It also genuinely requires that all of a transaction's log records be written before that transaction is genuinely allowed to commit, together ensuring recovery always has enough genuine information to correctly redo or undo any change.
A checkpoint periodically records the current genuine state of active transactions and flushes pending changes to actual, stable storage. It solves the genuine problem of a recovery process otherwise needing to replay the entire log from the genuinely very beginning of time after a crash, which would become impractically slow as the log genuinely grows larger over time.
The redo phase genuinely reapplies every change from committed transactions that might not have actually made it to stable storage before a crash. The undo phase genuinely reverses any change made by a transaction that was genuinely still active, and therefore uncommitted, at the exact moment the crash occurred.
ARIES (Algorithm for Recovery and Isolation Exploiting Semantics) is a genuinely widely-used recovery algorithm built on write-ahead logging. Its three core phases are analysis (determining what genuinely needs to be redone or undone), redo (reapplying all changes to genuinely restore the database to its exact state at crash time), and undo (rolling back genuinely uncommitted transactions).
Shadow paging maintains two genuinely separate page tables, a current one and a shadow copy, and a transaction genuinely commits by simply switching to the current table becoming the new genuine shadow. It's genuinely different from log-based recovery in that it avoids needing a genuinely separate log file at all, though it's less commonly actually used in modern systems due to real overhead and genuine fragmentation concerns.
Deferred update delays actually writing any change to the database itself until a transaction genuinely commits, so no undo is ever genuinely needed, since nothing uncommitted was ever actually written. Immediate update writes changes to the database as the transaction genuinely progresses, which requires both redo and undo capability, since an uncommitted change might already be reflected in the actual data when a crash occurs.
Parsing checks the query's genuine syntax and produces an internal representation. Query optimization actually generates and evaluates multiple genuinely possible execution plans, choosing the estimated cheapest one. Execution genuinely runs that chosen plan against the actual data to produce the final result.
An execution plan shows the exact genuine sequence of operations a database will actually perform to run a given query, including which indexes it plans to genuinely use, if any, and the join method chosen for each join. I'd specifically look for a full table scan on a genuinely large table where an index should have been used instead.
It relies on genuinely stored table statistics, row counts, the distribution of values in genuinely indexed columns, and estimated I/O and CPU cost for each specific operation, to genuinely predict roughly how expensive each candidate plan will actually be, choosing the estimated cheapest one overall.
If the query is genuinely expected to return a large fraction of the table's total rows, a full table scan can genuinely be faster than an index lookup followed by looking up each individual row it points to. Outdated table statistics can also genuinely cause the optimizer to make a poor choice, which is why keeping statistics reasonably up to date matters.
A nested loop join compares every row of one table against every row of the other, genuinely fitting a small table well. A hash join builds a genuine hash table on one side and probes it with the other, generally efficient for larger, unsorted data. A merge join genuinely requires both inputs already sorted on the join key, then merges them together in one genuinely efficient pass.
8-10 Years
A distributed database spreads data across multiple genuinely separate physical locations or machines, rather than storing everything in one single, centralized place. It solves the problem of a single database eventually genuinely outgrowing what one machine can practically handle in terms of storage, throughput, or geographic latency to actually reach users spread across the world.
Replication maintains multiple genuine copies of the same data across different nodes, improving availability and read performance. It introduces the genuine trade-off of keeping those copies actually consistent with each other, since a write to one genuine copy needs to somehow propagate to the others, either synchronously or asynchronously.
A quorum requires a read or write operation to be acknowledged by a minimum number of replica nodes before it's considered successful, rather than requiring every single replica to respond. Choosing read and write quorum sizes that together exceed the total number of replicas guarantees a read always sees the most recent write, giving a tunable middle ground between strict consistency and full availability.
Synchronous replication waits for a genuine replica to confirm it has received and applied a specific change before the primary considers that transaction actually committed, guaranteeing the replica is never genuinely behind but adding real latency to every write. Asynchronous replication commits on the primary immediately and sends the change to replicas separately afterward, which is faster but means a replica can genuinely, briefly lag behind.
Sharding distributes genuinely different subsets of data across multiple separate database instances, each instance holding only part of the genuinely total data, rather than replication's approach of each instance holding a genuinely full copy of everything. Sharding is used specifically when a dataset has genuinely grown too large for even one well-provisioned server to handle on its own.
The CAP theorem states that a distributed system can genuinely guarantee at most two of three properties at once: Consistency (every node sees the same data at the same time), Availability (every request gets a response), and Partition tolerance (the system keeps working despite a network partition). Since network partitions are a genuinely real possibility, the practical choice usually comes down to favoring consistency or availability when a partition genuinely occurs.
A distributed transaction needs to genuinely update data across multiple separate nodes as a single, atomic, all-or-nothing unit. It's genuinely difficult because there's no single shared database transaction spanning all of them, and coordinating a reliable, all-or-nothing outcome across multiple independent, network-connected nodes introduces real complexity a single-node transaction genuinely never has to deal with.
Two-phase commit coordinates a distributed transaction across multiple nodes through a genuine prepare phase, where every node confirms it's genuinely ready to commit, followed by a genuine commit phase, where every node actually applies the change together. It solves the genuine problem of ensuring every node either commits or aborts together, though it has real limitations around what happens if the actual coordinator itself genuinely fails mid-protocol.
Eventual consistency means that after an update, different nodes might briefly show slightly different, temporarily out-of-sync versions of the same data, but they'll eventually converge to a consistent state once all updates have fully propagated. It's an acceptable trade-off in many distributed systems because achieving strong consistency across independently-located nodes is genuinely expensive and can conflict directly with maintaining high availability during a network partition.
Database security protects data from genuinely unauthorized access, modification, or loss. Common techniques include authentication and authorization controls, encryption of genuinely sensitive data both in transit and at rest, and auditing access to genuinely track who accessed what and when.
SQL injection happens when genuinely untrusted user input is directly concatenated into a SQL query, letting an attacker genuinely manipulate the query's actual logic. Using parameterized queries, where user input is genuinely passed as a separate parameter rather than concatenated directly into the query string, prevents this entirely.
An operational database is optimized for fast, frequent reads and writes supporting genuine real-time transactions, typically highly normalized. A data warehouse is optimized instead for large-scale analytical queries scanning huge volumes of genuine historical data, often denormalized specifically to make those big, complex aggregate queries genuinely faster.
OLTP (Online Transaction Processing) handles genuinely frequent, small, real-time transactions, like a single order being placed. OLAP (Online Analytical Processing) handles genuinely complex, large-scale analytical queries scanning vast amounts of historical data, like a quarterly sales trend report. Each genuinely calls for a differently optimized database design.
Partitioning splits a genuinely very large table into smaller, more manageable physical pieces, typically based on a specific column like a date range, while the table still appears as one genuinely single logical table to any query run against it. It solves the problem of a single enormous table becoming genuinely slow to query and maintain.
I'd look at the actual, genuine access patterns and consistency requirements rather than choosing based on which technology happens to genuinely be more fashionable. Data with a genuinely flexible, frequently evolving schema and no strong requirement for complex joins might fit a NoSQL document store well, while data with real relationships that genuinely need to be queried together usually still fits a relational database better.
10+ Years
I'd look at the actual, concrete bottleneck first, is it genuine read load, which read replicas address directly, or is it genuinely a write-throughput or storage-size ceiling on a single instance, which typically requires sharding instead. Adding that architectural complexity before it's genuinely actually needed mostly just adds real operational overhead.
Run it incrementally wherever genuinely possible, keeping both the old and new systems running in parallel for a defined transition period, validating that data and query results genuinely match between the two, and cutting traffic over gradually rather than all at once in a single, genuinely high-risk switch.
I check whether the normalization level genuinely fits the actual, real access patterns rather than following normalization rules purely dogmatically, whether appropriate indexes are already planned for the specific queries the application will actually run most frequently, and whether the design will genuinely hold up as data volume grows substantially larger over time.
Automate what can genuinely be automated, schema linting and required-index checks run directly in each team's own CI pipeline, so standards aren't purely a matter of individual opinion. For standards that genuinely resist full automation, I'd document the handful of decisions that actually matter most, along with the real reasoning behind each one.
I'd weigh the genuine, actual growth trajectory and the real cost of a distributed system's own added operational complexity against how much further vertical scaling on a single, more powerful instance could genuinely still take the organization. Distributed complexity is worth it once vertical scaling genuinely, actually hits a real, concrete ceiling, not preemptively.
First check whether the actual test data volume genuinely resembles production, since a query that's fast on a small test dataset can genuinely become dramatically slower once the real, much larger production table is actually involved. Then I'd look specifically at lock contention and connection pool exhaustion under real concurrent load.
Track query latency, active connection count, replication lag if replicas are genuinely in use, and disk space over time, alerting on meaningful deviation from a normal, established baseline rather than relying only on a hard, static threshold. A slowly growing query latency trend is often a genuine early warning sign well before it causes a full outage.
Treat the schema as a genuine contract with every consumer. Adding a new, nullable column is generally safe. Renaming or removing an existing column needs a proper, communicated migration path, adding the new column first, migrating consuming code over, and only removing the old column once nothing genuinely still references it.
I'd check first whether the underlying table's data volume or actual shape has genuinely changed recently, and whether the query's execution plan has itself changed, since a database can silently switch to a genuinely worse plan once table statistics drift enough from what they were when the previous, faster plan was originally chosen.
Start from actual load testing against a realistically scaled-up dataset and traffic pattern, rather than a rough guess based purely on current traffic numbers. I'd specifically identify whether the coming bottleneck is genuinely likely to be read capacity, write capacity, or storage, since each of those calls for a meaningfully different scaling solution.
This is a judgment question interviewers use to see how you reason under genuine uncertainty, not to test a specific textbook fact. A strong answer names the actual constraint that forced the decision, the realistic options that were genuinely on the table, why you picked one knowing it wasn't guaranteed to be right, and what you'd do differently with what you know now.
I'd walk through one of their actual queries together against a realistically large dataset, showing the execution plan directly and pointing out concretely where the real cost is genuinely coming from, rather than just telling them the query is inefficient in the abstract. Seeing their own query's actual plan tends to shift how they write the next one far more effectively.
I wouldn't lead with normalization theory in the abstract. I'd point to a specific, already-experienced, real data inconsistency bug that traced directly back to redundant, poorly modeled data, and show concretely how a more disciplined design would have genuinely prevented that exact bug from ever happening.
I'd bring the actual query patterns and real, measured performance data behind my position, rather than a general, unsubstantiated preference for one particular approach. Most disagreements like this genuinely resolve once both sides are looking at the exact same concrete numbers together, instead of arguing from differing, unstated assumptions.
I'd translate the work into terms leadership already tracks: the cost of a specific past outage or slowdown that traced back to the current setup, and what continued growth in traffic or data volume would do to that same problem if left unaddressed. Framed as risk reduction with a concrete, already-incurred cost attached, it competes far better for prioritization than framed as a purely technical improvement.




