MySQL interview questions: InnoDB transactions and plans
Explain which read view and index access path a statement uses, then reason about the locks and invariant it protects. Evaluate schema and query changes against the exact InnoDB version and representative data.
Backend and data engineering roles using MySQL with InnoDB. · Practice guide, not an employer rubric. SQL snippets are illustrative and were not run against a database. Confirm behavior for the exact MySQL release, engine, schema and transaction settings.
Why does a primary key affect InnoDB secondary indexes?
InnoDB organizes table rows by the clustered primary key. Each secondary-index entry carries that key to locate its row, so a wide primary key increases secondary-index footprint.
Choose a primary key that is stable and reasonably compact, then index real filters and ordering. Randomness, monotonicity, key width and insertion patterns have different trade-offs; no single surrogate-key rule fits every workload.
Every extra index costs storage and work on inserts or indexed updates. Verify with the actual DDL and query plan before adding indexes reflexively.
SQL · Worked example
CREATE TABLE orders (id BIGINT NOT NULL PRIMARY KEY, tenant_id BIGINT NOT NULL, created_at DATETIME NOT NULL, KEY tenant_created (tenant_id, created_at, id)) ENGINE=InnoDB;
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: Why does a primary key affect secondary indexes?
InnoDB secondary-index entries carry the primary-key value used to find the clustered row. A wide key therefore affects index size and lookup work.
What differs between a consistent read and a locking read?
A normal consistent SELECT reads from a snapshot. SELECT ... FOR UPDATE is a current locking read for a transaction making an update decision.
Under InnoDB’s default REPEATABLE READ, consistent reads use a read view; locking reads and writes operate on current records. Lock ranges depend on isolation, index and scanned range, so a predicate can lock more than the returned rows.
Use the locking form when subsequent writes depend on the rows remaining available. Keep the transaction short and inspect the actual index path when contention surprises you.
SQL · Worked example
START TRANSACTION;
SELECT available FROM inventory WHERE sku = 'A17' FOR UPDATE;
UPDATE inventory SET available = available - 1 WHERE sku = 'A17';
COMMIT;
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: Why can a locking read behave differently from SELECT?
A locking read works with current records and takes locks based on the scanned index range. Choose it when a decision must reserve rows, not as a generic stronger SELECT.
Ordinary consistent reads in a transaction use a stable read view, while locking reads use current records. The label does not make every kind of read interchangeable.
InnoDB uses REPEATABLE READ by default. A transaction that mixes a snapshot SELECT with a locking read can see different versions because the operations have different purposes. Use a locking read, conditional update or constraint for a current-value invariant.
READ COMMITTED may reduce some gap-lock contention, but could change assumptions around phantoms and repeated reads. Change it only after reproducing the relevant interleaving.
SQL · Worked example
START TRANSACTION;
SELECT quantity FROM stock WHERE sku = 'A17'; -- consistent read
SELECT quantity FROM stock WHERE sku = 'A17' FOR UPDATE; -- locking read
COMMIT;
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: When might READ COMMITTED be considered?
When its reduced gap-lock behavior fits the invariant and contention profile. Test phantom-sensitive logic and concurrent writers before changing isolation.
What should an application do after an InnoDB deadlock?
Treat it as an aborted transaction, roll back and retry the whole idempotent unit a bounded number of times.
Deadlocks arise when transactions acquire incompatible locks in a cycle. InnoDB detects one and rolls back a victim. A retry must repeat the reads that formed the decision rather than rerun only the failed UPDATE.
Reduce recurrence by keeping transactions short and taking rows in deterministic order. Repeated retry exhaustion is an operational signal, not something to hide with an infinite loop.
Python-like pseudocode · Worked example
for attempt in range(max_attempts):
try:
transfer_in_one_transaction(source, destination, amount)
break
except DeadlockError:
if attempt + 1 == max_attempts:
raise
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: What must the application retry?
The whole transaction, including reads that informed it. Bound retries and make the transaction body safe to replay.
Use EXPLAIN to read access path, join order, estimated rows and chosen indexes. Compare estimates with actual behavior safely on representative data.
A large estimate error can indicate skew, stale statistics or a predicate that does not match an index prefix. Composite index order should follow the equality/range/order requirements the query actually has.
EXPLAIN ANALYZE executes the statement. For a write it can change data; use a disposable environment or a controlled reversible operation. Indexes also consume buffer-pool memory and add write work.
SQL · Worked example
EXPLAIN FORMAT=TREE
SELECT id, created_at FROM orders
WHERE tenant_id = 42 AND created_at >= '2026-01-01'
ORDER BY created_at DESC LIMIT 50;
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: How do you investigate a bad row estimate?
Check skew, statistics and index prefix alignment against representative values. Do not force an access path from one sample plan.
Use NOT NULL, UNIQUE, CHECK and foreign-key constraints for invariants that must survive concurrent writes. Validate at the application boundary too for clear errors.
A check-then-insert duplicate test races. A unique index arbitrates simultaneous requests. In MySQL 8.4, InnoDB enforces CHECK constraints; confirm server release and storage engine on older systems.
Choose foreign-key actions deliberately and plan existing invalid rows before adding constraints. A migration has locking and compatibility effects beyond the logical rule.
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: Why keep application validation if the database has constraints?
Validation gives early, useful feedback. Constraints remain the concurrency-safe integrity boundary and protect callers outside the current request path.
Use a composite order and cursor predicate for deep pages. A unique tie-breaker gives each result one position.
An order by created_at alone has ties. Include the primary key in ordering and cursor, with an index that starts from equality filters and supports the sort. Separate page requests still do not share one snapshot.
For an export that must represent a point in time, define a snapshot or high-water-mark policy. Keyset pagination solves deep skipping, not every consistency question.
SQL · Worked example
SELECT id, created_at FROM orders
WHERE tenant_id = ? AND (created_at, id) < (?, ?)
ORDER BY created_at DESC, id DESC LIMIT 50;
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: When can OFFSET still be reasonable?
For shallow pages or small stable result sets where random page numbers matter. Measure before adding cursor state.
What makes an index or constraint migration risky?
DDL has lock, I/O, disk and compatibility costs. Check the exact MySQL release, table and supported algorithm before planning the change.
Some ALTER operations can be instant or in-place under specific conditions; online does not mean zero metadata lock or resource use. Expand-and-contract keeps old and new application versions compatible while the schema changes.
Detect existing violations before adding a constraint. Observe disk headroom and replication lag during index creation in a safe rehearsal; this example does not authorize production DDL.
SQL planning sketch · Worked example
-- Planning query: locate duplicate values before a unique index.
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;
-- Resolve data and deploy compatible code before a separately planned migration.
Illustrative; use a disposable database and check the exact MySQL release and schema.
Illustrative, not executed.
Follow-up: How do you reduce migration risk?
Use expand-and-contract compatibility, validate old rows first, and check algorithm, locking, disk and replication impact for the exact server version.
These are Hacker News job posts that mention these technologies, not employee earnings or a measure of what a skill adds to pay. The amounts summarize annualized advertised minimums in approximate USD. Groups can overlap and differ in roles, locations and dates.
Approximate USD using ECB daily reference rates as of 2026-10-09. Original currencies and offer ranges remain on the source listings. These figures cover posts tagged MySQL, rather than every job in the broader technology family.