SQL interview questions decide a huge share of backend, data, and analytics hiring loops, because nearly every product runs on a relational database and a long tail of incidents ends in a query. This page is a complete, tiered bank: 104 questions with worked answers, split into beginner, intermediate, and scenario sections, plus hands-on labs, a cheat sheet of the statements that matter, and a knowledge check at the end. Work through it in order, or jump straight to the tier that matches your next round.

TL;DR
- 104 questions, three tiers. Beginner fluency, intermediate mechanics, and realistic scenario rounds, each answer shaped the way strong SQL interview questions are graded: name the mechanism, give the statement, add one production caveat.
- Depth over recall. Joins and their semantics, grouping and window functions, indexes and selectivity, EXPLAIN plans, transactions, isolation levels, locking, normalization, and query tuning, each explained at the layer the engine actually works.
- Practice is built in. Three scenario labs you can run on a local PostgreSQL or MySQL instance, a cheat sheet of the diagnostic statements that come up most, and a five-question quiz to check what stuck.
How the SQL interview works in 2026
Most SQL interview questions arrive in one of three rounds. The first is a screening call, often with a hiring manager or senior engineer, that mixes definitions with quick checks: the difference between a primary key and a unique constraint, WHERE versus HAVING, what a LEFT JOIN returns when the right side has no match. These are confidence filters. Nobody expects a lecture; they expect a crisp 30-second answer with exactly one level of detail behind it, and they listen for whether that detail is precise or padded.
The second round is the deep technical, and this is where SQL interview questions get mechanical. You write real queries, live or on a shared editor: multi-step aggregations, window functions, self joins, per-group top-N problems. Then the questions go under the syntax: why did the planner choose that index, what does selectivity mean, what changes when the table grows tenfold. Interviewers grade the second sentence, not the first. Saying the query uses an index passes a beginner bar; explaining that the planner estimated a handful of matching rows so a seek beats a scan passes a working-engineer bar. Most mid-level SQL interview questions are won or lost on that layer.
The third round is the scenario or troubleshooting round. You get one symptom sentence: the report that took 200 milliseconds now takes 20 seconds, a schema migration froze the checkout flow, two background jobs keep deadlocking every few minutes. What gets scored is your diagnostic order, not your luck. Engineers who say first I would read the plan, then compare estimated rows against actual, because that tells me whether the statistics or the access path is lying outperform engineers who start typing remedies. Most scenario SQL interview questions are lost by skipping the narration, not by missing the fix.
Role shape moves the emphasis. Backend loops weight SQL interview questions toward schema design, constraints, transactions, locking, and the queries an ORM quietly generates. Data engineering loops push toward bulk loads, window functions, partitioning, and idempotent pipelines. Analytics loops lean on joins, aggregation semantics, and date arithmetic. The base bank on this page is the same for all three; only the expected depth on each section moves, so prepare the whole bank and then lean into your lane.
Preparation that works is boringly mechanical. Install PostgreSQL or MySQL locally, run every query in this bank yourself at least once, and then rehearse the explanations out loud until each one takes 30 to 60 seconds spoken. If you can narrate every answer here without notes, you are ahead of most candidates, because most candidates read lists and never say the answers. Treat SQL interview questions as a performance under time pressure, and rehearse the scenario section the way you would rehearse a demo.
Core concepts interviewers expect you to know
Three mental models unlock a huge fraction of SQL interview questions: how the engine finds rows (indexes and the planner), how concurrent change is handled (transactions, isolation, locks), and how to read a query plan and act on it. Interviewers open here because these models sit under everything else on the page. If you can narrate all three fluently, most follow-up questions stop being new topics and become extensions of something you already explained.
Indexes: how the engine finds rows
An index is a persistent lookup structure, almost always a B-tree, that lets the engine go from a key value to the matching rows in logarithmic time instead of reading the whole table. The details that matter in interviews: the tree is balanced and shallow, leaf pages hold the entries and point at rows, and the optimizer weighs the index against a plain table scan using selectivity, the fraction of rows a predicate is expected to match. A column with a million distinct values across a million rows is highly selective and index-friendly; a boolean column is nearly worthless to index alone.
Three consequences generate half of the practical SQL interview questions about indexes. Composite indexes obey the leftmost prefix rule, so an index on (customer_id, created_at) serves filters on customer_id alone or customer_id plus a date range, but not on created_at alone. Covering indexes hold every column a query touches, so the engine never visits the table at all. And predicates like WHERE LOWER(email) = ? or WHERE created_at + interval '7 days' > now() hide the column from the index, which is why you rewrite the predicate or add an expression index. Every index also taxes writes and storage, which is the caveat strong candidates volunteer before being asked.
Transactions and isolation levels
A transaction is the unit of all-or-nothing change, and the ACID label is easier to defend once you say what enforces each letter. Atomicity comes from undo records that roll back partial work. Isolation comes from locks or, in modern engines, from multiversion concurrency control, where readers see a snapshot and never block writers. Durability comes from the write-ahead log, committed to disk before the engine acknowledges your COMMIT. Consistency is the outcome: constraints hold because everything else worked. Interviewers hear the difference between a candidate who recites the acronym and one who knows which subsystem delivers each guarantee, and that difference shapes the rest of the round.
The isolation ladder is the other guaranteed topic. Four levels trade concurrency for safety against dirty reads, non-repeatable reads, and phantoms, with engines picking different defaults: PostgreSQL defaults to READ COMMITTED, MySQL’s InnoDB to REPEATABLE READ, where gap locks suppress most phantoms. The senior edge is knowing the ladder is not the whole story: snapshot isolation still permits write skew, where two transactions read overlapping data and write disjoint rows that together violate an invariant, and only true serializable execution stops it. That nuance is one of the highest-signal SQL interview questions in circulation, because it separates people who memorized the matrix from people who have debugged it.
Reading the plan: how to think in EXPLAIN
Every query travels the same pipeline: the parser checks syntax and resolves names, the planner enumerates access paths and join orders, scores them with statistics and its cost model, and picks one; the executor then runs that plan operator by operator. EXPLAIN shows you the plan, and every scenario question about a slow query is secretly a question about reading it well. The fields to read first are the access type per table (seek, index scan, or full scan), the join algorithms chosen, and the estimated row counts, because a bad estimate cascades into a bad join order.
The habit to rehearse: compare estimates against reality with EXPLAIN ANALYZE, and treat a large gap between estimated and actual rows as a statistics problem before you treat it as an indexing problem. Watch for sorts that spill to disk, nested loops driving millions of executions, and functions applied to indexed columns. One caution worth saying out loud in any interview: EXPLAIN ANALYZE really executes the statement, so on INSERT, UPDATE, or DELETE you wrap it in a transaction and roll back, or you analyze a copy. That operational awareness is exactly what senior SQL interview questions are probing when they hand you a plan and ask what you would do next.
Question bank at a glance
The bank below is organized the way SQL interview questions are actually asked: broadly rising difficulty within each tier, then the scenario round that closes most loops. The counts are exact so you can pace a week of preparation: roughly fifteen beginner answers spoken aloud per day clears the bank in a working week, with the labs on the weekend.
| Section | Questions | What it proves |
|---|---|---|
| Beginner | 38 | You write SQL daily and the fundamentals are reflexes, not recall. |
| Intermediate | 40 | You know the machinery: indexes, planners, window functions, transactions, locking. |
| Scenario and troubleshooting | 26 | You can take a slow or broken database from symptom to cause in a defensible order. |
Difficulty rises inside each tier, so if a section starts feeling easy near its end, move on. Every answer pairs the mechanism with the statement or command and one production caveat, because SQL interview questions grade both halves: the right tool, and the right explanation of why that tool applies here and not everywhere.
Beginner SQL interview questions
These 38 are the warm-up tier of SQL interview questions. They look easy, and that is the trap: interviewers use them to check precision, not effort. Answer each in one or two sentences, then add exactly one supporting detail. Say more and you burn round time; say less and you sound like a memorized list. Deliver them crisply and the rest of the loop starts on your side of the table.
What is SQL, in one or two sentences?
Answer: SQL is the declarative language for relational databases: you describe the results you want, and the engine decides how to fetch or change them. It covers querying and modifying data, defining schemas, and controlling access. That declarative twist, specifying what rather than how, is the detail interviewers listen for, because everything about planners and optimization later in SQL interview questions flows from it.
What is the difference between SQL and MySQL or PostgreSQL?
Answer: SQL is the language; MySQL and PostgreSQL are database engines that implement it, the software that stores data, executes queries, and manages transactions. The analogy that lands: SQL is to MySQL what HTTP is to nginx. Engines differ in dialect, defaults, and tooling, so strong answers name the engine they actually used, which is precisely the habit SQL interview questions at screening level are fishing for.
What are DDL and DML statements?
Answer: DDL, data definition language, defines structure: CREATE, ALTER, DROP. DML, data manipulation language, works on rows: SELECT, INSERT, UPDATE, DELETE. The consequence worth adding: DDL usually takes schema locks and often cannot run safely on busy production tables without online procedures, which is why the DDL versus DML distinction shows up in operational rounds, not just vocabulary checkers.
What is a primary key?
Answer: The column, or column set, that uniquely identifies each row: implicitly NOT NULL, limited to one per table, and usually backed by an index, often the clustered one in InnoDB. It gives every row a stable address that foreign keys and replication rely on. It is among the most common opening questions in the whole genre, so name the three properties, unique, non-null, indexed, without hesitation.
What is a foreign key, and what does it enforce?
Answer: A foreign key is a column constrained to match values in a referenced table’s key, which enforces referential integrity: you cannot point an order at a customer that does not exist, and you cannot delete a customer whose orders would dangle unless the constraint defines an action like CASCADE. It moves integrity into the database where every writer obeys it, which is the sentence interviewers want from SQL interview questions about constraints.
What is a unique constraint, and how is it different from a primary key?
Answer: Both reject duplicates, but a table has one primary key, which forbids NULLs, while a table can carry many unique constraints, which in standard SQL and PostgreSQL permit multiple NULLs because NULL is never equal to NULL. Practically: primary key is identity, unique constraints are alternate business keys like email. That NULL subtlety is a reliable differentiator in written SQL interview questions.
What do NOT NULL and DEFAULT constraints do?
Answer: NOT NULL rejects inserts and updates that leave the column empty, and DEFAULT supplies a value when the insert omits one. They look trivial and are not: every nullable column doubles the branch count of the code that reads it, so deliberate nullability is a design decision, not an accident. Saying that consequence is what turns this small topic into a signal about schema judgment.
What is the difference between CHAR and VARCHAR?
Answer: CHAR stores fixed-length values padded to the declared width; VARCHAR stores variable-length strings with a length limit. CHAR suits two-letter country codes and hashes; VARCHAR suits almost everything else. Add the practical note that padding can silently break equality comparisons in some engines, and that overwide VARCHAR limits do not cost storage in PostgreSQL, where the limit is only a constraint, and you have covered what this question usually probes.
What is NULL, and how do you test for it correctly?
Answer: NULL means unknown or absent, not zero and not an empty string, and any comparison with it yields unknown rather than true or false. That is why = NULL matches nothing and the correct tests are IS NULL and IS NOT NULL. The downstream effects, COUNT(column) skipping NULLs and NULL falling last in most ORDER BY rules, are the follow-up SQL interview questions this answer invites, so volunteer one of them.
What does COUNT(*) count, and how is COUNT(column) different?
Answer: COUNT(*) counts rows, including rows where every column is NULL; COUNT(column) counts rows where that specific column is not NULL, so the two numbers differ exactly on nullable columns. COUNT(DISTINCT column) counts distinct non-null values. The trap, reporting active users with COUNT(email) while some rows have no email, is the reason COUNT variants keep appearing in reporting-accuracy rounds.
What does DISTINCT do, and what does it cost?
Answer: DISTINCT collapses duplicate rows in the result, which forces the engine to deduplicate, usually by sorting or hashing the whole result set before returning anything. It is often a smell: duplicates appearing usually means a join is fanning out rows, and DISTINCT papers over the real bug. Naming that habit is exactly what SQL interview questions on DISTINCT are listening for, because senior engineers fix the join instead of hiding its symptoms.
What is the difference between WHERE and HAVING?
Answer: WHERE filters rows before grouping, so it cannot see aggregates; HAVING filters groups after aggregation, so it can. WHERE status = 'paid' GROUP BY customer HAVING SUM(amount) > 1000 keeps only paid rows, then only customers whose paid total clears 1,000. Filtering early in WHERE is also cheaper, and saying why, fewer rows reach the aggregate, is the half of this entry in SQL interview questions that earns the second sentence.
What does GROUP BY do?
Answer: GROUP BY collapses rows that share the grouped values into one row per group, so aggregate functions can summarize each bucket: count, sum, average, min, max. Every selected column must be either grouped or aggregated, a rule engines like MySQL now enforce by default through ONLY_FULL_GROUP_BY. The mental model, buckets plus one aggregate per bucket, carries you through most grouping follow-ups without improvisation.
How do ORDER BY and LIMIT work together?
Answer: ORDER BY sorts the full result set, and LIMIT cuts it to the first N rows after that sort. The important consequence: without an index that already provides the order, the engine sorts everything and only then discards, so page 500 of OFFSET pagination gets slower with every page because it still builds and throws away the first 499 pages. Keyset pagination, WHERE created_at < last_seen, is the fix interviewers hope to hear about in SQL interview questions on pagination.
What is the difference between DELETE, TRUNCATE, and DROP?
Answer: DELETE removes rows one by one, fires triggers, can take a WHERE, and is fully logged. TRUNCATE removes every row fast by deallocating the table’s storage, usually cannot be filtered, and resets identity counters. DROP removes the table itself, schema and all. Choosing among them by intent, some rows, all rows, or the table’s existence, is the whole answer, and it is one of those SQL interview questions where the speed explanation matters as much as the definitions.
What does an INNER JOIN return?
Answer: Only the row pairs where the join condition matches on both sides: FROM orders o INNER JOIN customers c ON o.customer_id = c.id yields orders that have a matching customer and customers that have at least one order, nothing else. Non-matching rows vanish silently, which is the failure mode worth stating, because missing-data bugs caused by unnoticed INNER JOIN semantics are a staple of join rounds at every level.
What does a LEFT JOIN return, and when do you reach for it?
Answer: Every row from the left table, plus columns from the right where a match exists, filled with NULLs where it does not. Reach for it when the left side must survive regardless: all customers, including those with zero orders, which is how you count non-buyers by adding WHERE o.id IS NULL. That pattern, anti-join by LEFT JOIN plus NULL test, is one of the most rehearsed answers in SQL interview questions, so say it precisely.
What is the difference between UNION and UNION ALL?
Answer: UNION concatenates result sets and then deduplicates them, which costs a sort or hash over everything; UNION ALL just concatenates and keeps duplicates. If duplicates are impossible by construction or acceptable by design, UNION ALL is strictly cheaper. Interviewers like this pair because the performance reasoning, not the syntax, is the graded half in SQL interview questions about combining result sets.
What is a subquery?
Answer: A query nested inside another query, usable in the FROM clause as a derived table, in expressions like WHERE price = (SELECT MAX(price) FROM products), or with IN and EXISTS for membership tests. Uncorrelated subqueries run once; the correlated kind, next question, runs per outer row. Being able to classify a subquery by where it sits and how often it runs is the vocabulary that later performance questions assume you already have.
What is a correlated subquery?
Answer: A subquery that references columns from the outer query, so it conceptually re-runs once per outer row: WHERE price > (SELECT AVG(price) FROM products p2 WHERE p2.category = p1.category). That per-row execution is the performance story: it can degrade into a loop unless the optimizer rewrites it into a join or the inner query has a good index. Spotting one and stating its cost model is what SQL interview questions on subqueries are really grading.
What is a view, and why create one?
Answer: A view is a saved query with a name that behaves like a table: it stores no rows by default, just the definition, executed fresh at each use. Views centralize complicated or sensitive logic, give reporting a stable interface while tables evolve, and with column grants can expose some columns while hiding others. Mentioning materialized views, which do store results and must be refreshed, is the usual bonus point in SQL interview questions about views.
What is an index, in plain words?
Answer: A sorted lookup structure, typically a B-tree, that lets the engine jump close to the rows a predicate matches instead of reading the table end to end, the way a book index skips you to a page. The trade is real: every index speeds some reads and taxes every write plus storage. One sentence of mechanics plus the trade-off is the complete beginner answer, and it sets up the deeper SQL interview questions that come next.
What is a composite key?
Answer: A key made of two or more columns whose combination must be unique, classic in join tables like (student_id, course_id) for enrollments. It can back a primary key or a unique constraint, and it pairs naturally with the leftmost prefix rule once an index is built on it. That link between key design and index design is why composite keys open schema-reasoning rounds rather than syntax checks.
What is an auto-increment column, and what are its caveats?
Answer: A numeric column whose value the engine generates on insert: AUTO_INCREMENT in MySQL, identity or serial in PostgreSQL. Caveats worth naming: gaps are normal because rolled-back inserts still consume values, generated IDs leak business volume through the URL, and sequences live outside transactional rollback. Those three observations are the substance behind SQL interview questions about ID generation, and they signal you have inserted real data at scale.
What does the AS keyword do, and where can aliases be used?
Answer: AS names a column or table for the duration of the query: SELECT SUM(amount) AS revenue, FROM orders AS o. The rule people trip on: aliases declared in the SELECT list are not visible to WHERE, because WHERE runs conceptually before the select list is computed, but they are visible to ORDER BY. Knowing which clauses can see which aliases is a small precision check that surfaces often in written SQL interview questions.
What is CASE WHEN, and where does it shine?
Answer: CASE WHEN is SQL’s inline conditional: it returns a value per row based on ordered conditions, with an ELSE fallback. It shines in conditional aggregation, SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) builds per-status columns in one pass, and in translating codes to labels near the data. That pivot-table-in-one-query pattern is the working answer to most practical CASE prompts.
Why do single quotes and double quotes mean different things in SQL?
Answer: Single quotes wrap string literals; double quotes, or backticks in MySQL, wrap identifiers like table and column names, which is how you tolerate reserved words or mixed-case names. Confusing them is the classic error, and the security angle matters too: values belong in parameters, never concatenated into the statement. The literal-versus-identifier split is one of those small SQL interview questions that reliably separates people who type SQL from people who read it.
What is SQL injection, and what is the fix?
Answer: Injection is when untrusted input becomes part of the statement text, so the database executes attacker-authored SQL. The fix is parameterized queries: send SQL and values separately so the driver can never reinterpret a value as code, and ORM query builders help only if you never concatenate raw strings. Because one gap undoes every other control, injection remains the most security-weighted of the beginner SQL interview questions, so answer it without hesitation.
What is a transaction, in plain words?
Answer: A group of statements that succeeds or fails as one unit: money leaves one account and lands in the other, or nothing happens. BEGIN starts it, COMMIT makes it permanent, ROLLBACK undoes it. The sentence interviewers want in SQL interview questions here is why transactions exist: mid-failure states like a debit without its credit would otherwise be visible to other sessions, and that visibility is what isolation and atomicity jointly prevent.
What do COMMIT and ROLLBACK do?
Answer: COMMIT writes the transaction’s changes permanently, with durability guaranteed by the write-ahead log reaching disk; ROLLBACK discards them using the undo information the engine has kept since the first statement. After COMMIT, undoing requires a new compensating transaction, which is why production systems require confirmation before large commits. That permanence distinction is the operational half of this entry in SQL interview questions, and it matters in every incident story you will tell.
What is a self join?
Answer: A join of a table to itself using two aliases, so the engine treats it as two copies: FROM employees e JOIN employees m ON e.manager_id = m.id pairs each employee with their manager. It is the standard tool for hierarchical or pairwise questions within one table, org charts, referrals, upstream dependencies. Recognizing when a problem needs aliases is the pattern-recognition half of SQL interview questions about self joins.
What is normalization, in plain words?
Answer: Structuring tables so each fact lives in exactly one place: entities get their own tables, repeating groups become rows, and computed or duplicated values are removed so updates happen once and cannot drift out of sync. The cost is more joins on read. Delivering both halves, integrity won and read complexity paid, is what interviewers expect from SQL interview questions on normalization, because the trade is the point, not the textbook definitions.
What is the difference between a natural key and a surrogate key?
Answer: A natural key comes from the data itself, like a national ID or an ISBN; a surrogate is an engine-generated value with no meaning outside the table. Surrogates win in practice because real-world natural keys change, get reused, or arrive with typos, and updating a key cascades into every referencing table. Explaining why the industry defaults to surrogates, while keeping a unique constraint on the natural key, is the complete answer to this SQL interview questions staple.
What does the LIKE operator do, and what is its cost trap?
Answer: LIKE matches patterns: percent matches any run of characters, underscore matches exactly one. The trap is the leading wildcard: LIKE '%son' cannot use a B-tree index because the tree is sorted from the left, so the engine scans. Trailing patterns index fine, and leading-wildcard search is a signal to reach for full-text or trigram indexes. Knowing why the index refuses is the layer SQL interview questions on LIKE are testing.
When do you use IN, and when is EXISTS the better call?
Answer: IN tests membership against a list or subquery; EXISTS tests whether any matching row exists and stops at the first one. With small literal lists, IN is perfect. Against large subqueries, EXISTS often wins because it can short-circuit and pairs well with indexed probes, while a giant IN list gets materialized and scanned. Modern planners often rewrite one into the other, and saying that openly is the mature way to answer this SQL interview questions pairing.
How do you list the tables and columns of a database?
Answer: Query the catalog: information_schema.tables and information_schema.columns work across engines, while PostgreSQL also offers \dt and \d table in psql and MySQL offers SHOW TABLES and SHOW CREATE TABLE. Reading the schema from SQL itself is the portable skill, because scripts and migrations cannot rely on interactive clients. That catalog fluency is quietly checked in hands-on SQL interview questions, since it is how you explore an unfamiliar schema under pressure.
What is the difference between a database and a schema?
Answer: A database is the top-level container with its own users and storage; a schema is a namespace inside it that groups tables, views, and functions. PostgreSQL is schema-rich, one database with many schemas per project; MySQL effectively treats the two words as synonyms. The concrete use case, staging namespaces or multi-tenant separation inside one instance, is what elevates answers to SQL interview questions on this topic above the definition.
What is an upsert, and which syntax does each engine use?
Answer: An upsert inserts a row or, if the key already exists, updates it in one atomic statement: INSERT ... ON CONFLICT (email) DO UPDATE in PostgreSQL, INSERT ... ON DUPLICATE KEY UPDATE in MySQL. The atomicity is the point: check-then-insert from application code races under concurrency and loses, while upsert makes the database the referee. Race-safe writes are a recurring theme in modern SQL interview questions, and upsert is the canonical example.
Intermediate SQL interview questions
This tier is where SQL interview questions stop testing vocabulary and start testing mechanism. Forty questions follow, and the pattern to internalize is statement, then cause: name what you would run, then explain what the engine is actually doing and where it hurts. That second half moves you from query writer to engineer in an interviewer’s notes, and it is the habit that makes the scenario tier feel easy instead of scary.
What happens between submitting a query and the first row coming back?
Answer: The parser checks syntax and resolves names against the catalog; the rewriter applies rules and expands views; the planner enumerates candidate plans, scanning tables directly or through indexes, choosing join orders and algorithms, and prices each using statistics and its cost model; the executor then runs the winning plan, pulling rows through its operator tree. Most of that time budget goes to planning only for complex queries, and knowing the stages is what lets performance discussions get specific instead of hand-wavy.
How does a B-tree index actually locate a row?
Answer: The tree keeps keys sorted in its pages: a root page, intermediate levels, and leaf pages that hold index entries pointing at rows. A seek descends from the root, binary-searching each page and following one child pointer per level, so lookups cost a handful of page reads even on billions of rows, and the leaf level’s sibling links make range scans sequential. That page-and-pointer model, not the cartoon triangle, is what SQL interview questions on B-trees want you to narrate.
What is selectivity, and why does the optimizer care about it?
Answer: Selectivity is the fraction of rows a predicate is expected to keep, estimated from statistics like distinct counts and histograms. It drives everything: a highly selective predicate makes an index seek obviously cheaper than a scan, while a predicate matching 40 percent of a table usually wins by scanning sequentially because random index lookups cost more per row than a sequential read. Reasoning about percentages rather than absolutes is exactly the framing this topic deserves at intermediate level.
What is the leftmost prefix rule on a composite index?
Answer: A composite index is sorted by its first column, then the second within equal firsts, so it serves predicates on the leading columns contiguously: an index on (customer_id, status, created_at) supports customer_id alone, customer_id plus status, and all three, but not status alone or a date range on created_at alone. Equality columns should lead and range columns come last, because a range on an earlier column ends the usable prefix. Designing column order deliberately is the skill behind most SQL interview questions on composite indexes.
What is a covering index, and what does an index-only scan save?
Answer: A covering index contains every column the query references, so the engine answers from the index alone and never touches the table, shown as Using index in MySQL’s Extra or an Index Only Scan in PostgreSQL. It saves one random table access per matching row, which on a seek returning thousands of rows is the dominant cost. The trade, wider indexes and slower writes, is the caveat that rounds out any covering-index answer.
How does a clustered index differ from a secondary index, and where do heap tables fit?
Answer: A clustered index stores the table’s rows in the leaves of the primary key tree, InnoDB’s model, so the table is the index; secondary indexes store the key plus the primary key, so lookups through them pay one extra hop into the clustered tree. Heap tables, PostgreSQL’s model, keep rows unordered with all indexes pointing at physical row locations, which avoids that hop but makes fills and vacuum more visible. Choosing a clustered key that grows monotonically is the practical advice intermediate SQL interview questions on this topic are fishing for.
Why does wrapping an indexed column in a function defeat the index, and what are the fixes?
Answer: The index is sorted by the raw column values, so WHERE LOWER(email) = ? or WHERE created_at + 30 > now() asks the engine to sort by something it never stored, forcing a scan with per-row evaluation. Fix the predicate by shifting the computation to the constant side, create an expression index on exactly the function used, or, in MySQL 8 and PostgreSQL, index the generated form. Recognizing the pattern in a query handed to you is why SQL interview questions love this trap.
What is the difference between a table scan, an index scan, and an index seek?
Answer: A table or sequential scan reads every row and is optimal when you need most of them. An index scan walks the whole index, cheaper only because it touches fewer, narrower pages. An index seek descends the tree to a starting point and reads a contiguous range, the cheapest access when selectivity is high. Reading EXPLAIN’s access type and asking whether the count justifies the method is the working skill that plan-reading rounds keep returning to.
What does EXPLAIN output contain, and which fields do you read first?
Answer: The plan tree: each operator, its access method, estimated rows and cost, the join algorithm and order, and extras like sort method or whether the index covered the query. Read the estimated row counts first, because every join order decision downstream of a bad estimate inherits it; then the access type per table; then anything involving disk spills. In PostgreSQL add ANALYZE to see actuals, in MySQL use EXPLAIN ANALYZE since 8.0.18. That reading order is precisely what a scenario round expects you to narrate.
When do nested loop, hash, and merge joins each win?
Answer: Nested loop probes the inner side once per outer row, unbeatable when the outer side is small and the inner probe is an indexed seek; it is catastrophic when both sides are large. Hash join builds an in-memory hash table on the smaller side and probes it with the larger, winning for big equi-joins without useful indexes. Merge join consumes both sides in sorted order, efficient for large sorted inputs and the only natural choice for range conditions. Explaining the cost model behind each is the full answer to this SQL interview questions favorite.
What is a LATERAL join, and what problem does it solve?
Answer: LATERAL, CROSS APPLY in SQL Server, lets a subquery in the FROM clause reference columns from tables listed before it, so you can run a per-row correlated lookup that still reads like a join: the top three orders per customer, where the inner query sees each customer row. Before lateral joins this required correlated subqueries in SELECT or procedural loops. Naming one concrete top-N-per-group use is what SQL interview questions on LATERAL are after, since the syntax is useless without the use case.
How do window functions differ from GROUP BY?
Answer: GROUP BY collapses each group to one row, destroying the rows that built it; window functions compute an aggregate across a partition and attach it to every row, keeping all rows visible. AVG(amount) OVER (PARTITION BY region) puts the regional average beside every sale in that region, enabling comparisons without losing detail. They also run later in the pipeline, after grouping and HAVING, before ORDER BY. That keep-the-rows property is why interviewers open window-function rounds with exactly this comparison.
What is the difference between ROW_NUMBER, RANK, and DENSE_RANK?
Answer: All three order rows within a partition, and they differ on ties. ROW_NUMBER assigns unique sequential numbers regardless of ties, which makes it the tool for picking exactly one row per group. RANK gives tied rows the same number and skips the next numbers, so two second places are followed by fourth. DENSE_RANK also ties but never skips, following two seconds with third. Choosing ROW_NUMBER for dedupe and top-N tasks, and explaining the tie behavior, is the complete answer intermediate SQL interview questions expect here.
What are LAG and LEAD, and what do you build with them?
Answer: LAG pulls a column’s value from a previous row in the partition and LEAD from the next, with an optional default: LAG(total) OVER (ORDER BY month) puts last month beside this one, so growth is an expression, current minus LAG, with no self join. Sessionization, gap detection, and churn analysis all reduce to this pattern. Being able to reach for LAG instead of a contorted self join is one of the clearest level markers in modern SQL interview questions.
How do window frames like ROWS BETWEEN compute running and moving totals?
Answer: The frame clause controls which rows in the partition each calculation sees: SUM(amount) OVER (ORDER BY day ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) is a running total, and ROWS BETWEEN 6 PRECEDING AND CURRENT ROW is a seven-day moving window. With ORDER BY present the default frame is range-based up to the current row, which includes peer rows with equal order values, a subtlety that silently changes totals. Stating the default-frame nuance is the depth signal in SQL interview questions on window frames.
What is a CTE, and how does the engine actually run it?
Answer: A common table expression is a named subquery declared with WITH, usable like a temporary view for the duration of one statement, and referable multiple times; multiple CTEs chain into readable pipelines. Execution differs by engine: PostgreSQL inlines single-use CTEs into the outer query since version 12, unless you write MATERIALIZED, while MySQL typically materializes them once per statement. Those execution semantics, inlined versus materialized, decide whether the CTE is a label or a real performance boundary, which is exactly what SQL interview questions on CTEs are probing.
What is a recursive CTE, and what is it good for?
Answer: WITH RECURSIVE runs an anchor query, then repeatedly executes a recursive term that references the CTE itself, feeding each round’s output back in until it returns nothing: an anchor picking an org chart’s root, the recursive term finding each node’s reports. It handles traversal of adjacency lists, bill-of-materials explosions, and graph walks that fixed joins cannot express. Adding a depth counter and a cycle guard is the production caveat that completes any recursion answer.
What does each ACID property actually guarantee?
Answer: Atomicity: a transaction’s changes all apply or none do, delivered by undo records during rollback. Consistency: constraints hold at every commit boundary, as the outcome of the other three plus declarative constraints. Isolation: concurrent transactions do not observe each other’s partial work, delivered by locks or MVCC snapshots. Durability: once COMMIT returns, the change survives a crash seconds later, delivered by the write-ahead log being flushed before acknowledgment. Mapping each letter to the subsystem that enforces it is what separates rehearsed candidates in SQL interview questions on ACID.
What is MVCC, and why does it let readers and writers avoid each other?
Answer: Multiversion concurrency control keeps multiple versions of each row so readers get a consistent snapshot without acquiring read locks: writers create new versions, snapshots hide uncommitted or newer ones, and old versions are reclaimed by vacuum in PostgreSQL or by undo history in InnoDB. The consequence is that reporting queries no longer block OLTP writes, at the cost of storage bloat and the occasional snapshot-too-old error. Explaining both the win and the garbage-collection bill is what SQL interview questions on MVCC are listening for.
What is the difference between shared and exclusive locks?
Answer: A shared lock, taken by readers in lock-based engines, is compatible with other shared locks but not with exclusive ones; an exclusive lock, taken by writers, is compatible with nothing, so one writer excludes all other readers and writers on that row. Deadlocks and contention live entirely in the compatibility matrix, and MVCC engines rely on it mainly for writes while reads ride snapshots. Reciting the compatibility rule and its deadlock consequence is the standard pass on this SQL interview questions classic.
What is a gap lock or next-key lock, and what problem does it solve?
Answer: InnoDB under REPEATABLE READ locks not just matching rows but the gaps between them, next-key locks being the row lock plus the gap before it, so a range predicate like WHERE id BETWEEN 10 AND 20 FOR UPDATE blocks inserts of id 15 until the transaction ends. That is how a locking read prevents phantoms from appearing mid-transaction. The cost is real: gap locks collide on pure inserts, which is a leading source of deadlocks on hot tables, and naming that trade is the mature way to frame the feature.
What is the difference between optimistic and pessimistic concurrency control?
Answer: Pessimistic control locks target rows up front with SELECT FOR UPDATE, guaranteeing exclusive access at the cost of blocking others. Optimistic control reads freely and validates at write time, either by comparing a version column in an UPDATE … WHERE version = seen or by relying on the engine’s conflict detection, retrying on failure. Optimistic wins under low contention because nothing blocks; pessimistic wins under hot rows where retries would thrash. Framing the choice by contention level is the judgment SQL interview questions on this topic grade.
What does each standard isolation level actually prevent?
Answer: READ UNCOMMITTED allows reading uncommitted changes, so dirty reads are possible. READ COMMITTED adds the guarantee that you only read committed data, but re-reading a row can give a different value. REPEATABLE READ pins reads within your transaction to one snapshot, eliminating non-repeatable reads, while phantoms, new rows matching your predicate, remain possible in the strict ANSI reading. SERIALIZABLE makes concurrent execution equivalent to some serial order. Tying each step to a concrete anomaly, not just naming the ladder, is what intermediate SQL interview questions require on isolation.
What is write skew, and why do you need true serializable isolation to stop it?
Answer: Write skew happens when two transactions read an overlapping set, each makes a decision based on what they saw, and each writes to disjoint rows, so both commit and the invariant dies: two on-call doctors each see the other is on call and go off duty. Snapshot isolation permits it because neither write conflicts with a read it never made. Only serializable execution, PostgreSQL’s serializable snapshot isolation or InnoDB’s locking under SERIALIZABLE, detects and aborts it. That story is the canonical senior answer in SQL interview questions about anomaly hunting.
What is the write-ahead log, and why does it make commits cheap?
Answer: The WAL, InnoDB’s redo log or PostgreSQL’s WAL, records every change as a small sequential log entry that is flushed to disk before the transaction may commit; the messier random-page updates to data files happen later. Sequential appends are dramatically cheaper than random writes, so a commit costs one log flush rather than dozens of scattered page writes, and crash recovery replays the log forward. That order-of-operations argument, log first, data later, is the mechanism SQL interview questions on durability want named.
What do redo and undo records do during crash recovery?
Answer: Redo replays committed changes forward from the log so transactions that acknowledged COMMIT are not lost despite dirty pages never reaching disk. Undo reverses uncommitted work, restoring rows to their pre-transaction state, and its history also serves the MVCC snapshots readers need while recovery runs. Together they deliver the atomicity and durability promises with one mechanism. Explaining the two directions, forward for durability, backward for atomicity, is the crisp form of the whole answer.
What is a savepoint, and when is it useful?
Answer: A savepoint is a named marker inside a transaction, and ROLLBACK TO SAVEPOINT undoes work after the marker while keeping the transaction and earlier work alive: insert a thousand rows, and when batch 7 violates a constraint, roll back only batch 7 and continue. They are the tool for partial failure handling inside long transactions, best-effort imports above all. The caveat to volunteer in SQL interview questions: savepoints never substitute for keeping transactions short, because the locks still accumulate.
What do 1NF, 2NF, and 3NF each eliminate?
Answer: First normal form removes repeating groups and non-atomic values, one address list per cell becomes a child table. Second normal form removes partial dependencies, where a non-key column depends on only part of a composite key, so order line items stop storing product names keyed by product id alone. Third normal form removes transitive dependencies, where a non-key column depends on another non-key column, zip code implying city. Reciting the anomaly each form kills, with one example, is the whole of what SQL interview questions on normalization tiers demand.
When is denormalization justified, and what does it cost?
Answer: Denormalize when reads demand data in a shape normalization forbids: dashboards aggregating across many joins, per-user counters that would otherwise sum millions of rows, or cross-service reporting. Do it deliberately: keep the normalized tables authoritative, add the derived copy, and enforce sync with triggers, application logic, or scheduled jobs, accepting that the copy can drift and must be rebuildable from source. That governance framing, source of truth plus rebuild path, is what senior SQL interview questions expect from a denormalization answer.
What does ON DELETE CASCADE do, and what are its operational risks?
Answer: The foreign key action deletes dependent rows automatically when the parent goes: delete a customer, and orders, addresses, and sessions vanish. Risks worth naming: one accidental parent delete becomes a mass delete across tables, deep cascade chains make cleanup slow and lock-heavy, and the data loss is easy to underestimate during code review. Many teams prefer explicit application-level deletes with soft-delete flags. Stating both the convenience and the blast radius is what SQL interview questions on cascades are scoring.
What is plan caching and parameter sniffing, and when do they backfire?
Answer: Engines cache execution plans for prepared or repeated statements to skip planning cost, and the plan is optimized for the first parameter values the optimizer saw, which is parameter sniffing. It backfires when parameter distributions are skewed: the plan tuned for a rare customer id, an index seek, is catastrophically wrong for a predicate matching half the table. Remedies include plan recompilation, OPTIMIZE FOR UNKNOWN in SQL Server, generic plan checks in PostgreSQL, and rewriting so the plan is insensitive. Real-world war stories from this mechanism are a staple of senior SQL interview questions.
What is cardinality estimation, and how do stale statistics wreck plans?
Answer: The planner predicts how many rows each predicate and join will emit, using statistics: distinct counts, histograms, correlation. Every downstream choice, join order, join algorithm, access path, inherits those numbers, so a stale estimate after a data migration or a bulk load can flip a seek into a scan or pick the wrong hash side. The fixes are routine ANALYZE and auto-analyze tuning, larger statistics targets on skewed columns, and extended statistics for correlated columns. Connecting estimates to outcomes is the analytic core of SQL interview questions on plan quality.
What is a partial or filtered index, and when does it pay off?
Answer: A partial index, PostgreSQL’s WHERE clause or SQL Server’s filtered index, indexes only rows matching a predicate: CREATE INDEX ON orders (created_at) WHERE status = 'pending'. The pending backlog is a sliver of the table, so the index is tiny, hot in cache, and cheap to maintain, while queries carrying the same predicate use it. It shines on status-driven queues and soft-delete schemes. Naming the maintenance win, not just the query win, is what rounds out SQL interview questions on partial indexes.
What is an expression index, and how must the query be written to use it?
Answer: An expression or functional index stores the result of an expression as its key: CREATE INDEX ON users (LOWER(email)), with MySQL 8 supporting functional key parts like ((LOWER(email))). The optimizer uses it only when the query’s predicate contains the matching expression, so WHERE LOWER(email) = ? seeks it while WHERE email = ? does not. The matching-expression requirement trips people constantly, which is exactly why interviewers reach for it.
Why is LIKE ‘%term%’ slow on a B-tree, and what are the real alternatives?
Answer: A B-tree orders entries from the left, so a pattern without a fixed prefix cannot bound the search and must scan. The alternatives do real work: PostgreSQL’s pg_trgm extension indexes trigrams in a GIN index and serves arbitrary wildcard LIKE, full-text search with tsvector and GIN handles word-based relevance, MySQL’s FULLTEXT index serves MATCH AGAINST, and beyond the database, dedicated search engines take over. Choosing by use case, autocomplete versus relevance search, is the judgment this entry in SQL interview questions is really testing.
What is a deadlock mechanically, and how does the engine choose a victim?
Answer: A deadlock is a cycle in the wait-for graph: transaction 1 holds a lock transaction 2 needs while waiting on one transaction 2 holds, so neither can proceed. The engine’s detector finds the cycle, InnoDB checks continuously, PostgreSQL aborts on detection, and rolls back the transaction whose undo is cheapest, returning a deadlock error, MySQL 1213 or SQLSTATE 40P01, rather than waiting forever. Applications must retry, because a deadlock is a design signal, not a random failure. That retry-and-reframe point is what SQL interview questions on deadlocks exist to hear.
How do you observe blocking live in MySQL and PostgreSQL?
Answer: In MySQL 8, query performance_schema.data_lock_waits or the sys.innodb_lock_waits view for the waiter, the holder, and both statements; SHOW ENGINE INNODB STATUS adds the recent history and the last deadlock graph. In PostgreSQL, join pg_locks with pg_stat_activity and call pg_blocking_pids(pid) to name the blockers directly, or read pg_blocking_pids output per stuck pid. Both engines let you see waiter, holder, and SQL text in one screen. Being able to produce that query from memory is the practical bar intermediate SQL interview questions set for locking topics.
What is connection pooling, and why do applications need it?
Answer: Opening a database connection costs a TCP handshake, authentication, and, in PostgreSQL, a fresh backend process, milliseconds that dwarf a fast query. A pool keeps connections open and reuses them, bounding concurrency to a number the database can actually serve. The operational truths: every application instance needs a cap, sum them across instances and keep the total below max_connections, and poolers like PgBouncer or ProxySQL exist for fleets. Connection math under load is a recurring scenario theme in SQL interview questions, and pooling is its first answer.
When do you choose a temp table, a CTE, or a derived table?
Answer: A derived table or CTE keeps everything in one statement and reads cleanly; prefer it when the intermediate result is used once and is cheap to recompute. A temp table persists for the session, can be indexed and analyzed, and passes between statements or procedures, which is the right call for multi-step pipelines over genuinely expensive intermediates. The deciding questions are reuse and cost: used once, stay inline; reused or huge, materialize. That decision rule, not syntax recall, is what SQL interview questions on this trio grade.
What is wrong with cursors, and why is set-based SQL usually faster?
Answer: A cursor processes rows one at a time from the application or procedure, paying per-row round trips or context switches and denying the optimizer the chance to treat the whole set at once. The same logic in one UPDATE with a JOIN lets the engine batch, hash, and pipeline, typically orders of magnitude faster. Cursors remain legitimate for rare per-row side effects like calling a procedure per row. Saying when a cursor is actually acceptable is the nuance that lifts answers to SQL interview questions about set-based thinking.
Scenario and troubleshooting SQL interview questions
This tier is how scenario rounds actually feel: one symptom sentence, then the interviewer goes quiet while you think out loud. For every item below, the graded skill is the same, so state your order of checks and the reasoning behind it before you name a fix. A spoken diagnostic plan beats lucky typing almost every time, and that plan is what these scenario SQL interview questions are built to measure.
A report that took 200 milliseconds now takes 20 seconds after months of growth. What are your first steps?
Answer: Order of operations: capture the query and run EXPLAIN ANALYZE, since a plan that was right at a million rows can be wrong at ten. Read the access type and the estimated-versus-actual row counts first: a seek that became a scan, or estimates off by orders of magnitude, tells me whether I am looking at a statistics problem, an index that no longer covers the pattern, or a scan that was always borderline and got worse linearly. Only then act: refresh statistics, add or extend the composite index the plan is missing, or rewrite the query to filter before it aggregates. Narrating exactly that sequence is the entire grade here.
The same query uses an index seek in staging but a full table scan in production. Why?
Answer: The plans differ because the inputs differ, and I check four things in order. Data volume and distribution: production tables are larger and skewed, and a predicate that is selective on staging data can match half of production, where a scan is genuinely cheaper. Statistics: production estimates may be stale after heavy writes, so run ANALYZE and compare. Schema drift: the index may exist in staging and never have been created in production, which a diff of SHOW INDEX or pg_indexes settles in seconds. Server settings and versions: work_mem, cost parameters, and planner versions all shift decisions. Most real cases end at the first two, and enumerating the whole ladder is what distinguishes a strong answer.
Two background jobs keep deadlocking on the orders table every few minutes. How do you break the loop?
Answer: First capture evidence: enable innodb_print_all_deadlocks in MySQL or rely on PostgreSQL’s logging, then read the deadlock graph, LATEST DETECTED DEADLOCK in SHOW ENGINE INNODB STATUS, which names both statements and the exact locks. Almost always the cause is inconsistent access order: job A updates order 1 then 2 while job B updates 2 then 1. Fix in layers: make every writer touch rows in the same order, usually sorted by primary key; shorten transactions so locks live briefly; add retry-with-backoff on the deadlock error because detection is not prevention; and if a queue pattern is hiding underneath, use SELECT FOR UPDATE SKIP LOCKED so workers claim distinct rows. That evidence-then-ordering story is the canonical answer to deadlock SQL interview questions.
An ALTER TABLE adding a column stalled, and production requests piled up behind it. What happened, and what is the safe path?
Answer: The DDL needed a metadata lock, a long-running query or open transaction held one on that table, and the ALTER queued behind it; because metadata locks queue fairly, every query that arrived after the ALTER queued behind the ALTER, so the whole table went dark even though the DDL never started. Diagnosis: SHOW PROCESSLIST or pg_stat_activity shows the waiting DDL and, via pg_blocking_pids, the offender. The safe path: kill or let the offender finish, set a lock_timeout so future DDL fails fast instead of queueing, and use online procedures, MySQL’s ALGORITHM=INSTANT or INPLACE with LOCK=NONE, PostgreSQL’s metadata-only ADD COLUMN, or pt-online-schema-change and gh-ost for rewrites. Migration discipline is one of the most repeated scenario SQL interview questions because the failure mode is always in production.
You found duplicate customer rows with different IDs but the same email. How do you clean up safely?
Answer: In order: profile first with SELECT email, COUNT(*) FROM customers GROUP BY email HAVING COUNT(*) > 1 to size the problem; decide the canonical row per key, usually the earliest id or the one with recent activity; dry-run the merge plan, because foreign tables referencing the victims need re-pointing or deduplication too; then delete in a transaction using ROW_NUMBER, keeping rn = 1 per email and removing the rest, verifying counts before COMMIT; finally add a UNIQUE constraint on email so the bug cannot return, catching 1062 or 23505 in application code. Wrap-up: schedule the constraint addition before people forget. Duplicates plus constraints is the pairing that cleanup-focused SQL interview questions want demonstrated.
An ORM-backed endpoint fires hundreds of queries per page view. What is going on, and how do you fix it?
Answer: That is the N+1 pattern: the ORM runs one query for the list of posts, then lazily issues one query per post to fetch its comments, because the association was accessed inside a loop. Diagnose by counting statements per request, the ORM’s query log, or a general log sample. Fix by eager loading: a JOIN fetch or a second query with WHERE post_id IN, so the engine returns everything in one or two round trips; add dataloader-style batching where associations are conditional; and guard the fix with a statement-count assertion in tests. Demonstrating that you can name the pattern from a symptom, then prescribe the eager-loading fix, is exactly what N+1 SQL interview questions are built around.
Queries are fast when run alone but slow under production load. What do you investigate?
Answer: Isolation changes the machine, so I check in this order: waiting sessions, pg_stat_activity or SHOW PROCESSLIST, because a fast plan can queue behind lock holders; cache warmth, since a lone run finds everything in the buffer pool while production competes for it, visible as elevated read IO; plan switching, because prepared statements can flip plans depending on parameter values; and resource saturation, CPU run queues and I/O await from other tenants on the box. The tooling is wait-event sampling rather than EXPLAIN, because the plan is innocent here. Separating plan problems from wait problems is precisely the discrimination that scenario SQL interview questions under load are testing.
A reporting query sorts millions of rows and spills to disk. What are your options?
Answer: First confirm from the plan: an external merge sort line in EXPLAIN ANALYZE, or Using filesort in MySQL, proves the spill. Then attack in order of preference: eliminate the sort by giving the ORDER BY an index that already delivers the rows in order, composite columns matching filter-then-sort; reduce what reaches the sort by filtering earlier or pre-aggregating; and only then raise the memory knobs, work_mem in PostgreSQL or sort buffer settings in MySQL, knowing they are allocated per operation and per session, so a global bump can multiply dangerously. Explaining that per-operation memory math is the detail that separates strong answers to sort-performance SQL interview questions.
The slow query log is full of one query examining a million rows to return fifty. How do you get from that to the right new index?
Answer: Rows examined versus rows sent is a missing-index signature, so: run EXPLAIN and confirm a scan with a filter, not a seek; collect every predicate, join column, and the ORDER BY from the query, because an index must serve filter, then join, then sort in that priority; check selectivity of the leading column before writing anything, since indexing a low-cardinality flag alone rarely pays; create the composite index, re-run EXPLAIN ANALYZE, and confirm the seek plus a sane row estimate; finally, check for a near-duplicate index the new one makes redundant, because every extra index taxes every write. That walk from symptom to verified CREATE INDEX is the full arc that missing-index SQL interview questions want narrated.
A batch UPDATE must touch five million rows, and it keeps blocking the order API. How do you ship it?
Answer: Stop trying to do it in one transaction. Chunk the update: loop over primary key ranges, update a few thousand rows per transaction, commit, and sleep briefly between chunks so lock queues drain; keyset batching via WHERE id BETWEEN also keeps replication deltas small. Run it off-peak, watch pg_stat_activity or InnoDB lock waits and replica lag while it runs, and make the job resumable by tracking the high-watermark id, because it will be interrupted. Set a statement or lock timeout so a chunk fails fast instead of piling a lock queue behind itself. Chunked, resumable, watched: that trio is the deliverable in batch-job SQL interview questions.
The application reports “lock wait timeout exceeded”, but there are no deadlock errors. What is the difference, and what do you do?
Answer: A deadlock is a cycle the engine detects immediately and resolves by killing one side; a lock wait timeout means no cycle exists, but the holder is simply not releasing, so the waiter gave up after innodb_lock_wait_timeout, fifty seconds by default, or lock_timeout in PostgreSQL. So hunt the holder, not the waiter: find the oldest active transaction, an idle-in-transaction session from a crashed request path, or a long report holding shared locks; fix the code that opens transactions and stalls inside them; and set timeouts so interactive queries and schema jobs cannot hold locks indefinitely. Holder-versus-waiter reasoning is the entire point of this entry in scenario SQL interview questions.
One huge nightly transaction made replicas lag for an hour. What went wrong and how do you prevent it?
Answer: Replication applies a single large transaction atomically, MySQL’s applier and PostgreSQL’s WAL replay both serialize it, so a transaction touching millions of rows cannot be split downstream: the replica idles, then applies the whole thing in one burst, and Seconds_Behind_Master or replay lag spikes. The primary stays interactive while every replica reader sees stale data, which is the outage users actually notice. Prevent it by committing in chunks, so lag stays proportional to batch size, scheduling bulk work away from peak, and alerting on lag rather than discovering it from users. The atomic-apply mechanic is the explanation that earns full marks in replication-lag SQL interview questions.
SELECT COUNT(*) WHERE status = ‘active’ over 100 million rows is too slow for a dashboard. What do you propose?
Answer: Exact counts must touch the rows, so either make touching cheaper or stop needing exactness. Options in order: a partial index on the active rows makes the count an index-only scan over a sliver of the table; a cached counter, a summary table maintained by triggers or application increments, answers instantly but must be reconciled; a materialized view refreshed on a schedule trades staleness for speed; and an estimate from the planner’s row counts, or an approximate count function where the engine offers one, is often fine for a dashboard. Asking what precision the business actually needs first is the senior move in COUNT-performance SQL interview questions.
Users sometimes see stale data right after saving. How do you diagnose read-your-writes violations?
Answer: Assume replica lag until proven otherwise: the write lands on the primary, the next read hits a replica still replaying, and the user sees yesterday. Confirm by correlating timestamps: compare the primary write time against replica replay lag at that moment, and reproduce by writing then immediately reading through the read path. Fixes in order of preference: route the post-write read to the primary for that session or a short window, sticky sessions after writes; use monotonic reads where the driver or proxy offers them; and reduce lag itself by fixing the long transactions and bulk jobs causing it. Demonstrating the write-then-read correlation is the diagnostic craft this class of question rewards.
A query regressed right after an autovacuum or statistics refresh. How do you stabilize the plans?
Answer: First prove the cause: diff EXPLAIN output against the known-good plan and look at the row estimates that changed, because new statistics legitimately moved the numbers and the planner honestly picked worse. Then stabilize: raise the statistics target on the skewed columns so estimates stop swinging with each ANALYZE; add extended statistics where correlated columns mislead independence assumptions; force the known-good shape with planner hints such as pg_hint_plan, or SQL Server plan guides, as a bridge, not a destination; and if a version upgrade started the regression, check the upgrade notes for planner changes. Estimate-first reasoning is what separates regression-handling SQL interview questions answers from index-sprinkling.
A nightly bulk load dies halfway on duplicate keys, leaving partial data. What is your strategy?
Answer: Make the load atomic or idempotent, then choose. Atomic: load into a staging table with no constraints, validate and dedupe there, then INSERT into the target inside one transaction, or swap partitions if volumes are large, so a failure leaves the target untouched. Idempotent: ON CONFLICT DO NOTHING or ON DUPLICATE KEY UPDATE makes re-runs safe, though you should log the conflicts rather than silently swallowing data problems. Either way, fix the upstream duplicate generation too, because tomorrow’s run will collide again. Staging-table-then-swap is the pattern that earns the credit in bulk-load SQL interview questions, with idempotency as the running joke of every failed migration.
A developer ran an UPDATE without a WHERE clause on production. What now?
Answer: In order: if the session is still open and uncommitted, in PostgreSQL it holds row locks and nothing else has seen the damage, so roll it back immediately, which is the best case. If it committed, stop the bleeding: assess scope from the statement and binlog or WAL, then recover by restoring a replica or clone to before the statement and extracting the affected rows, or by targeted binlog inversion in MySQL where row images allow it. Communicate early, because legal and support may need to know what users saw wrong data. Then prevent: sql_safe_updates in MySQL, statement timeouts, restricted write access, and mandatory reviews for ad hoc production SQL. Recovery order under pressure is exactly what destructive-mistake SQL interview questions are scoring.
A unique constraint violation appeared in production despite validation in the application code. How, and what is the layered fix?
Answer: It is a race: two requests both ran the check, SELECT found no row, and both INSERTed before either committed, so application validation can serialize nothing by itself. The database is the only serialization point, so the fix is layered: keep the UNIQUE constraint as the final arbiter and catch 1062 or 23505, translating it into a friendly conflict response; replace check-then-insert with upsert, ON CONFLICT, where the intent allows it; and where the race is wider than one row, take SELECT FOR UPDATE on the shared parent row to serialize the critical section. The lesson, that constraint violations are concurrency findings, is the insight duplicate-race SQL interview questions exist to surface.
The database disk filled with WAL or binlog files. What do you check and tune?
Answer: Retention and slots, in that order. In PostgreSQL, a replication slot belonging to a decommissioned replica pins WAL forever, so check pg_replication_slots for restart_lsn that never advances, and review archive_command failures; then tune wal_keep_size and archiving. In MySQL, binlogs grow until binlog_expire_logs_seconds prunes them, and a stuck replica or a backup job mid-copy pins the purge, so check SHOW REPLICA STATUS first. Never delete WAL or binlog files by hand; the engine must be the one to reclaim them, or recovery breaks. Slot hygiene is the headline fix in WAL-growth SQL interview questions because it is the most common cause by far.
pg_stat_activity shows a session “idle in transaction” for hours, holding locks. What is happening and how do you fix it?
Answer: A client opened a transaction, executed something, and never finished it: an exception path that skipped rollback, an ORM with implicit transactions left open after a forgotten commit, or a developer’s terminal walked away from an editor session. The cost compounds: the snapshot blocks vacuum from reclaiming dead tuples, bloat grows, and its locks block everyone behind it. Immediate fix: terminate the session with pg_terminate_backend. Durable fix: set idle_in_transaction_session_timeout, and fix the code paths with try-finally or framework-managed transaction boundaries. Naming the vacuum-blocking side effect is the depth marker in idle-in-transaction SQL interview questions.
A three-table join over large tables times out. How do you approach rewriting it?
Answer: Diagnose before rewriting: EXPLAIN shows whether the join order is sane and whether any step is scanning when it could seek. Then reduce in stages: filter each table to the minimal row set first, in CTEs or derived tables, so joins happen over slivers instead of full tables; ensure join keys are indexed and statistics fresh; check the plan’s join order, and hint or restructure if a bad nested loop is driving billions of probes; consider materializing an expensive intermediate when it is reused; and if the pattern is permanent, pre-compute it, a summary table maintained incrementally. Stage-then-join is the mental model that join-rewrite SQL interview questions are fishing for.
You must change a 500 million row table’s column type with minimal downtime. What is the strategy?
Answer: Expand and contract. Add the new column alongside the old; deploy application code that writes both; backfill in keyset batches with sleeps, resumable and throttled, watching replica lag; verify with counts and checksums per range; flip reads to the new column behind a feature flag; stop writing the old one; and drop it last, since dropping is itself an online procedure on huge tables. Direct ALTER on that volume, where the engine rewrites the table, means hours of rebuild or a tool like gh-ost or pg_repack doing it with throttling. The phased contract, add, backfill, flip, drop, is the expected answer in big-migration SQL interview questions.
Analytics queries are hurting OLTP latency on the same instance. What are your options?
Answer: Separate by blast radius, cheapest first. Point analytics at a read replica so scans never share the primary’s caches and CPU, accepting lag; add workload isolation where the engine supports it, resource groups or workload management, to cap what reports can take; cache the hot aggregates so the same dashboard does not recompute every minute; and when volume or query shapes keep growing, move analytics to a real warehouse or column store fed by replication, which is the point where the OLTP and OLAP workloads stop pretending to share a machine. Replica-first staging is the pragmatic core of workload-contention SQL interview questions.
A search box using LIKE ‘%term%’ is timing out as the table grows. How do you redesign it?
Answer: The leading wildcard defeats the B-tree, so growth makes every search a full scan and the timeout is inevitable. Redesign by matching the need: word-level search with relevance wants a full-text index, tsvector with a GIN index in PostgreSQL or FULLTEXT with MATCH AGAINST in MySQL; substring autocomplete wants a trigram index, pg_trgm, which indexes fragments and serves arbitrary LIKE; and when requirements grow into facets, typo tolerance, and ranking, that is the honest moment to move to a dedicated search engine fed from the database. Matching the index type to the query shape is the design judgment search-rewrite SQL interview questions test.
You get “too many connections” at the daily traffic peak. What is your diagnosis path?
Answer: Connections pile up when queries are slow, so treat it as a symptom first: during the peak, count sessions by state in pg_stat_activity or SHOW PROCESSLIST, and if hundreds are active, the real problem is those queries; if hundreds are idle in transaction or sleeping, application code is leaking or over-opening. Then do the connection math: pool size times application instances against max_connections, because twelve instances with default pools of fifty overflow almost any database. Remedies in order: fix the slow query holding connections, right-size pools, put PgBouncer or ProxySQL in front for multiplexing, and tune connection timeouts so dead clients release. Peak-time connection accounting is the full answer this scenario SQL interview questions wants.
A “latest order per customer” query built with GROUP BY returns wrong rows. Why, and what is the correct pattern?
Answer: GROUP BY collapses each customer’s orders to one row, and any column that is neither grouped nor aggregated comes from an arbitrary surviving row, so the max amount and the order id can come from different orders. MySQL’s ONLY_FULL_GROUP_BY now rejects it outright. Correct patterns, best first: ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_at DESC) in a CTE, filtered to rn = 1, which is portable and deterministic; PostgreSQL’s DISTINCT ON (customer_id) with matching ORDER BY; or a correlated subquery on MAX(created_at) where the planner handles it well. Name-and-fix with a window function is the canonical shape of greatest-per-group SQL interview questions.
Hands-on scenario labs
Reading answers builds vocabulary; reflexes need repetition, and the scenario tier of SQL interview questions is graded on reflexes. Each lab below runs on a throwaway local database, PostgreSQL preferred, MySQL where noted, and takes under twenty minutes. Do each three times: once with the checklist open, once from memory, once narrating out loud as if an interviewer were listening, because that narration is exactly the rehearsal scenario rounds reward.
Lab 1: hunt a slow query with EXPLAIN
- Create the playground:
CREATE TABLE orders (id bigserial PRIMARY KEY, customer_id bigint, status text, created_at timestamptz DEFAULT now());then load a million rows withINSERT INTO orders (customer_id, status) SELECT (random()*99999)::int, (ARRAY['new','paid','shipped'])[1+floor(random()*3)] FROM generate_series(1,1000000); - Run
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;and read the plan: Seq Scan, estimated rows versus actual, execution time. - Add the fix candidate:
CREATE INDEX ON orders (customer_id);then re-run the EXPLAIN ANALYZE and compare plan, rows, and time out loud. - Break the statistics on purpose: insert a large burst for one customer, run
EXPLAINwithout analyzing, note the stale estimate, then runANALYZE orders;and watch the estimate correct itself. - Close by writing down, from memory, the three plan fields you read first and why they come in that order.
Lab 2: manufacture and solve a deadlock loop (MySQL)
- Create
CREATE TABLE t (id INT PRIMARY KEY, n INT);with rows for ids 1 and 2, then open two mysql sessions and runSTART TRANSACTION;in both. - Build the cycle: session A runs
UPDATE t SET n = n + 1 WHERE id = 1;, session B runs the same for id 2, then A updates id 2 and B updates id 1. - Watch one session receive error 1213, then read the
LATEST DETECTED DEADLOCKsection ofSHOW ENGINE INNODB STATUSand name both statements and both held locks out loud. - Enable
SET GLOBAL innodb_print_all_deadlocks = ON;, reproduce once more, and find the deadlock graph in the server log. - Fix it: have both sessions update ids in ascending order, rerun the loop, and confirm no deadlock fires.
Lab 3: find and remove duplicates safely
- Insert a few rows sharing the same email into a copy of your orders-adjacent customer table, so duplicates exist with distinct ids.
- Find them:
SELECT email, COUNT(*) FROM customers GROUP BY email HAVING COUNT(*) > 1;and predict the canonical row for each group before querying further. - Delete keep-one in a transaction: rank with
ROW_NUMBER() OVER (PARTITION BY email ORDER BY id)in a CTE, delete where rn > 1, verify the counts with a SELECT, then COMMIT. - Prove the recurrence is dead:
CREATE UNIQUE INDEX ON customers (email);then attempt a duplicate insert and observe the constraint error. - Repeat the delete from memory on a fresh copy, narrating each step’s purpose as if the interviewer asked why.
Cheat sheet: the commands behind the answers
Nearly every item in this bank of SQL interview questions resolves to one of the statements below, in the same order you would reach for them live. Learn the table, then learn one sentence of reasoning per row, and you can walk any scenario round without improvising.
| Statement | What it tells you |
|---|---|
EXPLAIN SELECT ... | The plan: access type, join order and algorithm, estimated rows |
EXPLAIN ANALYZE (PG) / MySQL 8 equivalent | Real timing and rows per operator; run carefully on writes |
SHOW INDEX FROM t / \d t | Which indexes exist and on which columns |
ANALYZE t | Refreshed statistics so estimates match reality |
SELECT ... FROM pg_stat_statements ORDER BY total_exec_time DESC | The queries actually costing the most time |
SELECT * FROM sys.statements_with_full_table_scans | MySQL suspects for missing indexes |
SELECT pid, state, query FROM pg_stat_activity | Who is running what right now, and who is idle in transaction |
SHOW FULL PROCESSLIST | MySQL’s live session list and current statements |
pg_blocking_pids(pid) | The sessions holding the lock a waiter is stuck on |
SELECT * FROM sys.innodb_lock_waits | MySQL waiter, holder, and both statements in one view |
SHOW ENGINE INNODB STATUS | Last deadlock graph, lock waits, history list length |
SET GLOBAL innodb_print_all_deadlocks = ON | Log every deadlock, not just the most recent |
SELECT ... FOR UPDATE | Lock the rows you are about to change, pessimistic path |
SELECT ... FOR UPDATE SKIP LOCKED | Workers claim jobs without colliding on the same rows |
SET SESSION TRANSACTION ISOLATION LEVEL ... | The isolation your session actually runs under |
START TRANSACTION / COMMIT / ROLLBACK | Group statements into one all-or-nothing unit |
CREATE INDEX CONCURRENTLY (PG) | Index builds that avoid a long table lock |
ALTER TABLE ... ALGORITHM=INSTANT, LOCK=NONE | MySQL’s online DDL controls for busy tables |
INSERT ... ON CONFLICT DO NOTHING / ON DUPLICATE KEY UPDATE | Race-safe upserts that make the database the referee |
SELECT k, COUNT(*) ... GROUP BY k HAVING COUNT(*) > 1 | Duplicate business keys, the first step of any dedupe |
ROW_NUMBER() OVER (PARTITION BY k ORDER BY id) | Keep exactly one row per key when cleaning duplicates |
VACUUM (ANALYZE) t / OPTIMIZE TABLE t | Reclaim dead tuples or rebuild, and refresh statistics |
Authoritative details for every plan node mentioned here live in the PostgreSQL EXPLAIN documentation, and MySQL’s optimizer behavior is documented in the MySQL 8.0 optimization manual, both worth skimming before a round that leans on one engine.
Key takeaways and FAQ
The through-line of every tier above: SQL interview questions reward people who pair a statement with its mechanism. The statement alone reads as memorization; the mechanism alone reads as theory; together they read as someone who has been paged for a slow report at 2 a.m. and fixed it without guessing. Carry that pairing into every answer you rehearse and the bank above becomes a script for the whole loop.
How long should I prepare for SQL interview questions?
With daily SQL use, a focused week: two days speaking the beginner tier aloud, two on the intermediate mechanics, one on scenarios, the weekend on the labs. Without regular practice, plan three to four weeks, because the intermediate tier only sticks if you have run EXPLAIN on real tables and watched estimates mislead you at least once.
Are SQL interview questions different for data analysts and backend engineers?
The beginner tier is identical. Analysts get heavier weighting on joins, aggregation semantics, and window functions, with less on locking; backend engineers get transactions, constraints, isolation levels, ORM behavior, and migration safety. Prepare the full bank either way, because panels mix, and scenario rounds borrow from both halves.
Do I need to know a specific engine for SQL interview questions?
Know one engine deeply and say which one it is; interviewers respect specificity. The concepts here, B-trees, MVCC, isolation anomalies, plan reading, transfer across engines, but defaults differ, PostgreSQL ships READ COMMITTED and InnoDB ships REPEATABLE READ, and quoting the wrong default is the kind of small miss interviewers notice. Depth on one engine plus vocabulary on the other covers nearly every loop.
How many SQL interview questions should I practice per day?
About fifteen answers spoken aloud per day clears this bank in a week, which is the right pace only if each answer is delivered, not skimmed. The speaking is the practice: candidates who read twice as many answers silently consistently underperform candidates who say fewer out loud, because the round rewards formulation under time pressure.
What separates senior answers in SQL interview questions?
Three habits: naming the mechanism the engine uses, not just the syntax; volunteering the operational caveat, write cost of indexes, replication lag of big transactions, lock queues behind DDL; and giving the diagnostic order for scenario questions before any fix. Seniors also know when the answer is it depends and can list the two or three facts that would decide it.
What should I read after this page?
Continue with the Linux interview questions bank, since database performance work happens on machines you will also be asked about, and the MongoDB interview questions bank for the document-store counterpart teams love to compare against SQL. Then browse the DevOps Prep hub for the rest of the series as it ships.