Project Interview Bible β‘ Recently updatedUpdated on Jun 30, 2026 β this content may still be evolving.
Explaining Database Design in Your Project
Interviewers want to see you understand your data model β not just that you used an ORM.
What to Cover
- Main entities and relationships
- Why you chose SQL or NoSQL
- Key indexes and why
- One query you optimized or would optimize
- How you handle migrations/schema changes
How to Present Your Schema
Step 1: Name Your Entities (30 seconds)
βMy app has four main entities: Users, Posts, Comments, and Likes. Users create posts. Users comment on posts. Users like posts.β
Step 2: Draw ER Diagram (60 seconds)
users ββββββββββ< posts
β β
β β
ββββββββ< comments >β
β
ββββββββ< likes >ββββ posts
Use crowβs foot notation or simple arrows. Label relationships: one-to-many, many-to-many.
Step 3: Show Key Tables (60 seconds)
users (id, email, name, password_hash, role, created_at)
posts (id, user_id FK, title, body, image_url, created_at)
comments (id, post_id FK, user_id FK, body, created_at)
likes (user_id FK, post_id FK) -- composite PK
SQL vs NoSQL β Your Justification
| If you used PostgreSQL/MySQL | If you used MongoDB |
|---|---|
| βData has clear relationships β users own posts, posts have comments. JOINs are natural." | "Document structure matched my nested data β a blog post with embedded comments." |
| "Needed transactions for [payments/order placement]." | "Rapid prototyping β schema evolved a lot during development." |
| "Team and I are more comfortable with SQL." | "Mongoose gave me validation and easy Node.js integration.β |
Honest upgrade path: βIf I needed complex reporting or strict relationships, Iβd choose Postgres. MongoDB was fine for MVP.β
Relationships Explained Simply
| Type | Example | Implementation |
|---|---|---|
| One-to-many | User β Posts | posts.user_id foreign key |
| Many-to-many | Users β Groups | Join table group_members(user_id, group_id) |
| One-to-one | User β Profile | profiles.user_id unique FK |
Many-to-many example (students in courses):
students (id, name)
courses (id, title)
enrollments (student_id, course_id, enrolled_at)
-- composite PK on (student_id, course_id)
Indexing (Interview Gold)
What to Say
βI added an index on
posts(user_id, created_at DESC)because the profile page queries all posts by a user sorted by newest first. Without it, Postgres does a full table scan.β
Common Indexes in Student Projects
| Query pattern | Index |
|---|---|
| Get posts by user, newest first | INDEX (user_id, created_at DESC) |
| Login by email | UNIQUE INDEX (email) |
| Feed: posts from followed users | INDEX (user_id, created_at DESC) on posts |
| Search by title | GIN INDEX on to_tsvector(title) (Postgres full-text) |
How to Find Slow Queries
βIβd run
EXPLAIN ANALYZEon my feed query. If it shows Seq Scan on a large table, I add an index on the filtered/sorted columns.β
Normalization vs Denormalization
Normalized (default):
-- Like count requires COUNT query
SELECT p.*, COUNT(l.user_id) as like_count
FROM posts p LEFT JOIN likes l ON p.id = l.post_id
GROUP BY p.id;
Denormalized (faster reads):
-- like_count stored on posts table, updated on like/unlike
posts (id, title, body, like_count DEFAULT 0)
What to say: βI denormalized like_count on the posts table because itβs displayed on every feed item. I increment/decrement it in the same transaction as the like insert/delete. Slight risk of drift if a transaction fails β Iβd add a periodic reconciliation job at scale.β
Migrations
If using Prisma:
βSchema changes go through Prisma migrations. I run
prisma migrate devlocally, commit the migration SQL, andprisma migrate deployruns automatically on Railway deploy.β
If using raw SQL:
βI keep migration files in
/migrationsnumbered sequentially. Each file is a forward-only SQL script. I never edit production data manually.β
Interview question: βHow do you add a column without downtime?β
βAdd nullable column first β deploy code that writes to it β backfill existing rows β add NOT NULL constraint if needed. Never drop and recreate in production.β
Sample Schema Walkthrough (Blog App)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) DEFAULT 'user',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE posts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(200) NOT NULL,
body TEXT,
published BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_posts_user_created ON posts(user_id, created_at DESC);
CREATE TABLE comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
post_id UUID NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
body TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_comments_post ON comments(post_id, created_at ASC);
Talking points:
ON DELETE CASCADEβ deleting a user removes their posts and commentsUUIDvsSERIALβ βUUIDs are harder to guess, safe to expose in URLsβupdated_atβ βtrack when post was last editedβ- Indexes match actual query patterns
Common Interview Questions
Q: How would your schema change for 1 million users? A: βAdd indexes on all foreign keys and sort columns. Consider read replicas for feed queries. Partition large tables by date if we have years of data. Archive old posts.β
Q: N+1 query problem β what is it?
A: βFetching a list of posts, then looping to fetch each authorβs name β 1 + N queries. Fix with JOIN or Prisma include: { author: true } to batch in one query.β
Q: How do you handle soft deletes?
A: βAdd deleted_at TIMESTAMPTZ column. Queries filter WHERE deleted_at IS NULL. Preserves data for audit; can hard-delete later.β
Q: Why UUID over auto-increment? A: βNon-guessable in URLs, safe to generate client-side, no collision across distributed systems. Tradeoff: larger storage, slightly slower indexes than integers.β
Checklist
- Can draw ER diagram in 60 seconds
- Can explain each relationship type in your schema
- Know at least one index you added (or would add) and why
- Can explain one normalization/denormalization choice
- Know how you run migrations