SQL System Design & Problem-Solving Master Report
Senior-Level Interview Prep Guide
1. CORE SQL GOTCHAS & FUNDAMENTALS
1.1 NULL Handling — The Most Common Trap
The Rule: Comparisons with NULL always return UNKNOWN, never TRUE or FALSE. Rows filter out.
Incorrect Approaches (These Fail):
Correct Approach:
Interview Insight: Any senior engineer should immediately catch NULL comparison errors. This filters when it shouldn’t — data silently disappears from results.
1.2 DISTINCT Placement — Single Application Rule
The Rule: DISTINCT applies once, to the entire result row after SELECT. It cannot be repeated per column.
Incorrect:
Correct:
Interview Insight: Show understanding of WHERE the DISTINCT token sits in the execution model, not just that it removes duplicates.
1.3 Ambiguous Column References in Joins
The Rule: When a column name exists in both tables and isn’t qualified, MySQL throws an ambiguous reference error.
Errors Occur When:
| |
Solution: Always Qualify:
Interview Insight: This catches junior developers. Senior engineers alias defensively from the start, even with single-table queries. Shows discipline and prevents silent bugs when schemas evolve.
2. AGGREGATION & GROUPING RULES
2.1 WHERE vs. HAVING Execution Order
Critical Rule: WHERE runs before grouping/aggregation. HAVING runs after.
Consequence: You cannot reference SELECT aliases or aggregates in WHERE.
This Fails:
This Works:
Also Works:
Interview Insight: Explain the execution order to show deep understanding. Many seniors get this wrong under pressure.
2.2 GROUP BY with Non-Aggregated Columns
MySQL Behavior (with ONLY_FULL_GROUP_BY OFF):
This works syntactically but semantically is weak — unclear which is_active value you get per group.
Best Practice: Include all non-aggregated columns in GROUP BY or use aggregate functions:
Interview Insight: Know the MySQL setting. Know when it’s safe to break this rule (e.g., deterministic single-value columns you’re confident about), but default to full correctness.
2.3 HAVING Can Reference Aliases (But Not All Databases Do)
MySQL Allows:
Safer (Portable):
Interview Insight: Mention MySQL’s permissiveness, but show preference for standard SQL (re-compute the aggregate in HAVING). Demonstrates database portability awareness.
3. FORMATTING & DISPLAY ISSUES
3.1 ROUND() Returns Numeric Type — Trailing Zeros Lost
The Problem:
Numeric types don’t store trailing zeros; they only matter for display.
Solutions:
Option 1: FORMAT() — String with Formatting
Option 2: CAST to DECIMAL — Keeps Type, Preserves Decimals
Interview Insight: Show awareness of the difference between value and display. Know when to use a string (reports, client-facing) vs. keeping numeric type (further calculation).
3.2 ORDER BY After Formatting — Critical Bug
The Bug:
Result: Alphabetic sort of strings like “99.58”, “99.18”, “98.92”, “90.22”, “9.85” ← Jumps here!
Because as strings: "9.85" < "90.22" (character-by-character: ‘9’ vs ‘9’, ‘.’ vs ‘0’, and ‘.’ < ‘0’ in ASCII).
Fix: Sort Before Formatting
Interview Insight: This is a real production bug. Sorting after casting to strings silently corrupts results. Always sort on the raw column; format in the SELECT list only for display.
4. QUERY OPTIMIZATION PATTERNS
4.1 CTEs for Readability & Maintainability
Use Case: Multi-level aggregation or deeply nested subqueries.
Before (Hard to Maintain):
| |
After (Clear, Maintainable):
| |
Benefits:
- Named steps make intent clear
- Easy to modify without parenthesis hell
- Often better query plan optimization
- Easier to test intermediate CTEs independently
Interview Insight: Refactoring ugly nested subqueries into CTEs shows seniority. Interviewers love this — it’s professional code.
4.2 Joins Over Nested Subqueries (With Caveats)
When It Works Well: Simple 1:N or N:1 joins often outperform nested subqueries at scale.
When Be Careful: Blindly converting aggregation subqueries to joins can cause double-counting if cardinality changes:
| |
Interview Insight: Show nuance. Not all subqueries are bad; nested aggregations especially need care when converting. Suggest JOINs but justify why and acknowledge the cardinality risk.
4.3 When to Use ORDER BY Column Position
Safe:
| |
Risky (Maintenance): If someone later adds a new column in position 2, the sort changes silently:
Best Practice:
| |
Interview Insight: Mention you know column-position sorting exists (older SQL style), but show preference for named columns in modern code. Demonstrate awareness of technical debt and maintenance burden.
5. SYSTEM DESIGN PATTERNS
5.1 Data Mart for Recurring Multi-Source Analytics
Problem:
- Multiple data sources (OLTP, OLAP, etc.)
- Complex joins taking 45+ minutes
- Performance degradation during peak hours
- Different teams concerned about cross-system query impact
Solution: Purpose-Built Reconciliation Data Mart
| |
Benefits:
- Report queries complete in seconds, not 45 minutes
- OLTP/OLAP systems only touched during controlled scheduled extracts
- Single, optimized structure for the specific use case
- Data quality layer can validate/reconcile before mart population
Interview Insight: Shows understanding of data warehouse patterns and decoupling. Demonstrates thinking beyond “just write a good query” to architectural solutions.
5.2 Table Partitioning for Time-Series Operational Data
Problem:
- Monitoring table grows 50GB/month (18 months = 900GB)
- Real-time queries on recent data slow during peak hours
- Policy: keep 3 months readily accessible, 12 months for trend analysis, older archived
Solution: Monthly Partition + Tablespaces
| |
Query Impact:
| |
Benefits:
- Peak-hour queries on recent data stay fast (partition pruning)
- Aged data moves to cheaper storage, not deleted (compliance)
- New partitions auto-added; old ones aged out systematically
- Scales indefinitely with predictable performance
Interview Insight: Show awareness of operational vs. analytical workloads. Demonstrate thinking about retention policies, compliance, and cost. Partitioning is a senior-level tool.
5.3 Staging Area + Controlled Extraction
Pattern: Intermediate buffer for cross-system data loads, decouples source systems.
| |
Interview Insight: Staging area is a common enterprise pattern. Shows awareness of data quality, lineage, and decoupling live systems from analytical workloads.
6. DECISION FRAMEWORK FOR SENIOR INTERVIEWS
6.1 When You See a Problem, Ask These Questions
| Problem Type | First Question | Likely Approach |
|---|---|---|
| “Make query faster” | Real-time or batch? | Index, partition, or data mart |
| “Reduce storage” | Is data still needed? | Compress, archive, or partition to cheaper storage |
| “Handle multiple sources” | How often does reporting run? | Staging area + mart, or federation |
| “Ugly nested query” | Is this for production or report? | Refactor to CTE or replace with JOIN (with cardinality check) |
| “Report takes 45 mins” | Who queries it? When? | Dedicated data mart, scheduled load |
| “Schema change breaks queries” | How often does this happen? | Better documentation, CI/CD validation, or alias defensively |
6.2 Red Flags & Gotchas to Catch in Code Reviews
- Comparing to NULL → Use IS NULL / IS NOT NULL
- ORDER BY after FORMAT() → Sort the raw column; format in SELECT
- Blindly converting subqueries to JOINs → Check cardinality, especially with aggregates
- GROUP BY with non-aggregated, non-functional columns → Add to GROUP BY or aggregate
- WHERE clause filtering on aliases → Move logic to HAVING or pre-filter in FROM
- Ambiguous column names (unqualified) → Qualify all columns in multi-table queries
- Single table query running 45+ minutes → Partition, index, or redesign with staging
- Hardcoded DISTINCT without understanding scope → Justify; it applies to the entire row
7. INTERVIEW TALKING POINTS
Opening Statement (When Asked to Optimize/Design)
“Before I propose a solution, I’d ask: What’s the current performance bottleneck? Is this a real-time query or a batch report? Who runs it, when, and how often? Are there retention/compliance requirements? That context drives whether I’m optimizing the query itself, refactoring to CTEs, introducing indices, building a data mart, or partitioning the table. There’s rarely one answer.”
On Refactoring Nested Subqueries
“I’d first convert deeply nested subqueries to CTEs for readability — that’s often a productivity win before touching performance. Then, if it’s still slow, I’d check if we can use JOINs instead. But I’d be careful: if there are aggregates, converting to a JOIN can cause double-counting if I’m not accounting for cardinality correctly. A DISTINCT or GROUP BY can fix that, but I’d validate the results match the original query.”
On Partitioning & Archival
“Partitioning solves multiple problems at once: it keeps recent data queries fast (partition pruning), allows older data to move to cheaper storage without deletion, and lets you implement retention policies systematically. The trade-off is administrative overhead — you need a job to create new partitions and age out old ones. For a 50GB/month growth rate, this pays for itself quickly.”
On Data Marts
“If the same complex query runs repeatedly against live systems, a data mart is usually the answer. You extract and pre-aggregate data on a schedule, then users query the mart. It decouples your analytics workload from production, gives you a validation layer, and makes every subsequent report query instant. The cost is latency — data is as fresh as your last load — but for most reporting, daily or hourly loads are fine.”
8. QUICK REFERENCE CHECKLIST
Before writing any query:
- All columns in GROUP BY or aggregated?
- WHERE vs. HAVING logic separated correctly?
- NULL handling explicit (IS NULL / IS NOT NULL)?
- Joins qualified (table.column)?
- ORDER BY on raw columns, not formatted/casted?
- Result cardinality as expected?
Before proposing optimization:
- Real-time or batch?
- Current bottleneck: query plan, storage, or architecture?
- Retention/compliance requirements?
- Cross-system or single-source?
- Does a data mart make sense?
- Should this be partitioned?
Before refactoring:
- Does this improve readability?
- Does this hurt performance (test first)?
- Does this maintain correctness (especially cardinality)?
- Will future maintainers understand this?
9. PRACTICE SCENARIOS
Scenario A: Slow Daily Report
Given: A daily financial reconciliation report joining sales (OLTP), costs (OLAP), and inventory tables. Report takes 45 minutes; users complain during 9 AM daily standup.
Senior Answer:
- First, I’d check: Is the report truly needed to be real-time, or can it run at 6 AM?
- If it can run off-hours, build a data mart: extract, validate, and pre-join the three tables nightly. Report queries then run in seconds.
- If real-time is non-negotiable, add indices on the join keys (sales.product_id, costs.product_id, inventory.product_id) and ensure statistics are fresh.
- Avoid the three-table join in the mart if possible; instead, pre-aggregate from sales and costs separately, then LEFT JOIN to inventory only if inventory levels are truly needed (they often aren’t for profit reporting).
Scenario B: NULL Handling Bug
Given: A query filtering active customers returns fewer rows than expected after a code change.
Buggy Code:
| |
Senior Answer:
If any status values are NULL, they’re silently filtered out (NULL != ‘inactive’ returns UNKNOWN, not TRUE). Fix with:
Then ask: What should NULL status mean? Incomplete signup? And should the upstream schema default status to something explicit instead?
Scenario C: Partitioning Strategy
Given: A logs table with 100GB/day growth; compliance requires 90 days retention; queries are usually on the last 7 days.
Senior Answer: Daily partitions (not monthly, too granular for this scale). Set an automated job to create tomorrow’s partition and drop partitions older than 90 days. Route recent partitions to fast SSD storage, older partitions to cheaper HDD/cloud storage. Query performance stays flat as data grows; no one notices the 90-day retention boundary operationally.
10. FINAL REMINDERS
- Correctness first, optimization second. A slow query is better than a fast wrong one.
- Ask clarifying questions. The best senior engineers ask before proposing.
- Explain trade-offs. Partitioning, data marts, and CTEs all have costs. Own them.
- Test your assumptions. Don’t guess at cardinality or performance; measure.
- Think operationally. How will the DBA monitor this? Who on-calls? Will it scale?
- Show your work. Interviewers care as much about your reasoning as your answer.
Last Updated: August 2026
Prepared for: Senior ML Engineer / Senior Data Engineer Interviews
Focus: AdTech, Production Systems, and Scalability