skip to content

Keys & Integrity Constraints

How a relational engine enforces data correctness declaratively — keys, uniqueness, referential integrity, and row predicates checked on every write. Interviewers probe this to see whether you push invariants into the database or rely on racy application checks.

part ofRelational database conceptsoverview, primer and where to startread it →
on this pageshow

questions

page 2 of 2

Rank the per-row write cost of a CHECK constraint, a UNIQUE constraint, and a FOREIGN KEY constraint on the same table, and explain what makes them differ by orders of magnitude.

level: middleimportance: should knowfreq 32%

basics

~20 s

CHECK is cheapest: pure CPU on the row's own column values, no extra pages, no locks. UNIQUE costs an index probe plus an index write. FOREIGN KEY costs a probe into another table plus a lock on the parent row held to commit, so it is the only one that makes writers contend.

open as a page

Compared with a plain non-unique index on the same column, what extra work does a unique index perform on every INSERT, and why can engines not defer or buffer that work the way they can for non-unique index maintenance?

level: middleimportance: should knowfreq 45%

basics

~20 s

Both write a leaf entry. The unique one must first read the key's position and prove no live duplicate exists, and if another uncommitted transaction inserted the same key it must wait for that transaction to finish. That read and that wait cannot be deferred.

open as a page

Why can a CHECK constraint not enforce a rule such as 'at most one active row per customer' or 'this value must exist in another table', and what mechanisms do relational engines offer instead?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A CHECK sees only the single row being written, so it cannot inspect other rows or other tables, and mainstream engines forbid subqueries in it. Cross-row rules need a different mechanism: a unique or partial unique index, a foreign key, an exclusion constraint, or a trigger.

open as a page

Once a unique constraint is the mechanism preventing duplicate rows, how should the write path be structured around it — catching the constraint-violation error, or using an insert-if-absent statement — and what changes for the surrounding transaction?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Catch the violation when a duplicate is genuinely an error the user should hear about; use an insert-if-absent statement when a duplicate is a normal outcome. Match on the constraint name, not the message text, and remember an error may abort the transaction unless you wrap the insert in a savepoint.

open as a page

A batch job opens a transaction, issues SET CONSTRAINTS ALL DEFERRED, and then performs a few million writes. What operational consequences does that have — for error reporting, for concurrent sessions, and for the transaction's resource use?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Violations now surface at COMMIT with a constraint name but no guilty statement, and the entire batch is lost. The engine queues one pending check per affected row, costing memory. Concurrent sessions see nothing invalid, but hold-open locks last longer.

open as a page

You need to make an existing nullable column NOT NULL on a busy table of 200 million rows, with no maintenance window. Describe a rollout that avoids holding a long exclusive lock.

level: seniorimportance: should knowfreq 32%

basics

~20 s

Stop the app writing NULLs, backfill existing NULLs in small batches, add CHECK (col IS NOT NULL) NOT VALID (brief lock), validate it under a weak lock, then SET NOT NULL — which PostgreSQL 12+ can do without rescanning because the validated CHECK proves it.

open as a page

SQL Server lets you add a CHECK or FOREIGN KEY constraint WITH NOCHECK so existing rows are not verified. What state does that leave the constraint in, what does the query optimizer do differently as a result, and how would you find and repair such constraints later?

level: seniorimportance: should knowfreq 24%

basics

~20 s

The constraint is enforced for new writes but marked untrusted, so the optimizer will not reason from it — losing simplifications like join elimination and predicate-based partition elimination. Fix by cleaning the data, then ALTER TABLE ... WITH CHECK CHECK CONSTRAINT to rescan and re-trust it.

open as a page

When a transaction inserts a row whose foreign key column references a parent row, what lock does the engine take on that referenced parent row, and why not simply an exclusive row lock?

level: seniorimportance: should knowfreq 42%

basics

~20 s

It takes a shared, key-preserving lock on the parent row — enough to stop the parent being deleted or its key changed before commit, but weak enough that many children can be inserted concurrently. An exclusive lock would serialise every child insert under the same parent.

open as a page

A developer creates a unique index on a lookup table's code column, then tries to add a foreign key from another table referencing that column, and the database refuses with 'no unique constraint matching given keys'. What does the referenced side actually have to provide for a foreign key to be legal?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The referenced columns must be provably unique for every row of the table. The standard requires a declared PRIMARY KEY or UNIQUE constraint; engines that accept a bare unique index still require it to be full-table, non-partial, over plain columns and immediately checked. Partial and expression unique indexes never qualify.

open as a page

A table keeps soft-deleted rows using a deleted_at timestamp, and the business rule is 'at most one live account per email address' while deleted rows must be retained. How do you enforce that rule in the database?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Plain UNIQUE (email) is wrong — it blocks re-registering a deleted address. Enforce it with a partial (filtered) unique index on email restricted to rows where deleted_at IS NULL. Where partial indexes are unavailable, index a generated column that holds the email only for live rows.

open as a page

A rule requires that at most one row per customer may have an empty (NULL) discount code — that is, uniqueness must treat two NULLs as equal. What options does a relational database give you, and what does each cost?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Three routes: declare the key with NULLS NOT DISTINCT where the engine supports it (SQL:2023, PostgreSQL 15+); replace NULL with a non-null sentinel and use an ordinary unique constraint; or add a partial unique index over the rows where the column IS NULL. The sentinel is the portable choice.

open as a page

A DELETE that removes a single row from a parent table occasionally runs for minutes and blocks other sessions. Explain how deleting one row can generate a very large amount of write work, and how you would bound the blast radius.

level: seniorimportance: should knowfreq 35%

basics

~20 s

Cascading referential actions multiply: one parent row deletes all its children, each child deletes its own children, and every deleted row costs table and index maintenance, logging and a lock held to commit. Bound it by deleting in batches yourself, archiving instead of deleting, or dropping whole partitions.

open as a page

How do you decide which business rules belong in database constraints, which belong in application code, and which need a different mechanism entirely?

level: principalimportance: should knowfreq 38%

basics

~20 s

Put stable, structural, row- or table-scoped invariants in the schema; put volatile or contextual policy in code. Rules the engine cannot express — cross-service, aggregate, temporal — need an explicit mechanism such as index-based enforcement, serialisable transactions, or asynchronous reconciliation with alerting.

open as a page

Product wants email addresses to be unique in a 100-million-row users table that currently contains duplicates, and there is no maintenance window. Lay out the rollout you would run, including how you decide when it is safe to enforce.

level: principalimportance: should knowfreq 26%

basics

~20 s

Settle the semantics, enforce in the application first, dedupe the history in batches, build the unique index without blocking writes (CREATE UNIQUE INDEX CONCURRENTLY / ONLINE=ON), then attach it as a constraint with a brief lock. Uniqueness has no unvalidated mode, so the index build is the staging mechanism.

open as a page

Some engines historically parsed CHECK constraint syntax but never enforced it — MySQL accepted and ignored CHECK clauses before version 8.0.16. What are the practical consequences of an unenforced constraint, and how would you verify that a constraint in a given database is actually enforced?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

The schema claims an invariant the data does not have: bad rows accumulate silently, and code that trusts the constraint breaks later. Verify empirically — attempt an insert that must fail. If it succeeds, the constraint is decoration, and you need application checks plus a data audit.

open as a page

An architect proposes declaring every constraint in the schema DEFERRABLE so that batch jobs can always rely on commit-time validation. Would you adopt that as a default? Justify the call.

level: principalimportance: nice to knowfreq 22%

basics

~20 s

No. Keep constraints NOT DEFERRABLE by default and make individual ones deferrable where a real cycle or swap demands it. Blanket deferrability costs error attribution and pending-check memory, restricts features like upsert conflict inference, and hides modelling problems.

open as a page

You are setting the schema convention for a large database: should uniqueness always be declared as a named table constraint, or are bare unique indexes acceptable? How would you decide, and what follows from the choice?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Default to named constraints: they are the objects foreign keys, upsert targets and schema tooling can cite, and they are hard to delete by accident. Allow bare unique indexes only where constraint syntax cannot express the rule — conditional or computed uniqueness — and document each exception.

open as a page

You are modelling an optional identifier — most rows will not have one, but when present it must be unique — and the schema has to behave identically on PostgreSQL, MySQL and Microsoft SQL Server. How do you approach the design?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Do not let correctness depend on engine NULL rules, which disagree. Either move the optional identifier into its own table where the column is NOT NULL and uniquely constrained, or keep it in place with an engine-specific object (filtered index on SQL Server, plain unique constraint elsewhere) chosen deliberately.

open as a page

showing 31–48 of 48