SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

Database DesignTroubleshooting

Debug common issues with root cause analysis

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore Database Design Team
Expert Content

Database Design — Troubleshooting

A query is slow despite having what looks like the right index

Run EXPLAIN ANALYZE before assuming anything — check whether the planner is actually using the index at all (it might be choosing a sequential scan anyway, which can be correct for a query returning a large fraction of the table, see Intermediate). If it's using the index but still slow, check whether the index actually matches the query's filter/sort columns in the right order (a composite index's column order matters — see Fundamentals/Interview) and whether statistics are stale (ANALYZE tablename; refreshes the planner's row-count estimates, which can be badly out of date after a large bulk insert/delete and cause the planner to make a poor choice).

Foreign key constraint violation on an insert that "should" be valid

Check whether the referenced row genuinely exists at the moment of the insert, in a transaction-aware way — a common real cause in concurrent systems: the parent row is being inserted in the same transaction but hasn't actually committed yet when the child insert runs, or a race condition where the parent row was deleted by a concurrent transaction between when your application checked for its existence and when it attempted the insert. Wrapping related inserts in a single transaction (parent then child, both committed together) is usually the correct fix, not removing the constraint.

`ON DELETE CASCADE` deleted more data than expected

This is a design issue more than a bug — CASCADE deletes everywhere the deleted row's key is referenced, transitively, if those child tables also have CASCADE foreign keys onward. Before adding CASCADE, trace the full dependency chain explicitly (what actually cascades, how many levels deep) rather than assuming it only affects the immediately obvious child table — a chain of cascading deletes across several tables can remove far more data than a quick glance at one foreign key definition suggests.

Normalized schema requires too many joins for a common query, hurting performance

This is the exact scenario denormalization (Intermediate) exists to address — but before denormalizing, confirm with EXPLAIN ANALYZE that the joins are actually the bottleneck (versus missing indexes on the join columns themselves, which is a much smaller, safer fix than denormalizing). Adding proper indexes on foreign key columns used in joins often resolves join-performance problems that look like they'd require denormalization, without taking on denormalization's data-duplication tradeoff at all.

Migration fails partway through, leaving the schema in an inconsistent state

Check whether your migration tool wraps each migration in a transaction by default (most do, but not universally, and some DDL statements in some databases can't run inside a transaction at all, which is a real, specific limitation worth knowing about for your specific database engine). If a migration can't be transactional for that reason, it needs to be written to be safely re-runnable (idempotent) or to have an explicit, tested rollback script — "just re-run the migration" is not a safe recovery plan if the migration isn't actually idempotent and partially applied changes are already in place.

A composite unique constraint isn't preventing the duplicate you expected it to block

Check column order and null handling specifically — a UNIQUE (a, b) constraint allows multiple rows where either a or b is NULL, since SQL's standard null-handling treats NULL as not equal to anything, including another NULL — this is a common, genuine surprise for people expecting NULL to behave like a regular comparable value in a uniqueness check. If you need to treat NULL as a real value for uniqueness purposes, you need an explicit workaround (a partial unique index with a WHERE column IS NOT NULL clause, or using a sentinel value instead of NULL), not the plain constraint as written.

Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Up Next
🏆
Database DesignCertification
Exam prep and practice
Also Worth Exploring
← Back to all Database Design modules
Interview Q&ACertification