Reading Query Plans: practice questions
400 questions in four levels, all on RetailMart, the practice database of this course. Write every query yourself, get it wrong, read the error, fix it. That is how it sticks.
Answers are coming soon. Post your query in the WhatsApp Community or Discord and we will check it together.
Easy 100 questions Medium 100 questions Hard 100 questions Crazy 100 questions
Core syntax, applied directly
CONCEPTUAL Q1 What does EXPLAIN show vs EXPLAIN ANALYZE? Q2 Does EXPLAIN (without ANALYZE) run the query? Q3 Does EXPLAIN ANALYZE actually execute the query? Caution for writes? Q4 What is a Seq Scan and when is it chosen? Q5 What is an Index Scan and when is it chosen? Q6 What is a Bitmap Index Scan / Bitmap Heap Scan (rough idea)? Q7 In "cost=0.00..431.00", what do the two numbers mean? Q8 What's the difference between estimated rows and actual rows? Q9 Why is a big gap between estimated and actual rows a warning sign? Q10 What does "rows" vs "loops" mean in EXPLAIN ANALYZE? Q11 What is a Nested Loop join (intuition)? Q12 What is a Hash Join (intuition)? Q13 What is a Merge Join (intuition)? Q14 Why is "SELECT * on a wide table" often wasteful? Q15 Why does LIKE '%abc' (leading wildcard) defeat a B-tree index? Q16 Why does WHERE UPPER(email) = '...' prevent index use? Q17 Why add LIMIT to exploratory queries? Q18 What does "actual time=...rows=..." tell you about a node? Q19 What does ANALYZE (the maintenance command) do, vs EXPLAIN ANALYZE? Q20 What does EXPLAIN (BUFFERS) add? Q21 What does EXPLAIN (FORMAT JSON) give you? Q22 Why read a plan bottom-up (leaves first)? Q23 What is the "actual rows" you multiply by loops to get total work? Q24 Why might the planner pick a Seq Scan even when an index exists? Q25 Name two analyst query smells you can spot from a plan alone. RUN EXPLAIN Q26 EXPLAIN a SELECT of all orders for one cust_id. Q27 EXPLAIN a SELECT of orders in a date range. Q28 EXPLAIN a COUNT(*) of sales.orders. Q29 EXPLAIN a join of orders to customers on cust_id. Q30 EXPLAIN ANALYZE the same join; note actual time. Q31 EXPLAIN a query filtering products by price > 5000. Q32 EXPLAIN a query with ORDER BY net_total DESC LIMIT 10. Q33 EXPLAIN a GROUP BY cust_id SUM(net_total). Q34 EXPLAIN ANALYZE a WHERE email LIKE 'a%' on customers. Q35 EXPLAIN ANALYZE a WHERE email LIKE '%gmail.com' (leading wildcard). Q36 EXPLAIN a WHERE UPPER(email) = '[email protected] '. Q37 EXPLAIN a 3-table join (orders->order_items->products). Q38 EXPLAIN (ANALYZE, BUFFERS) a customer aggregate. Q39 EXPLAIN a SELECT * FROM web_events.page_views LIMIT 100. Q40 EXPLAIN ANALYZE a query with no LIMIT on page_views (then add LIMIT). Q41 EXPLAIN a query with an OR across two columns. Q42 EXPLAIN a query with IN (subquery). Q43 EXPLAIN a query with EXISTS (subquery). Q44 EXPLAIN a DISTINCT on order_status. Q45 EXPLAIN ANALYZE a HAVING COUNT(*) > 5 grouping. Q46 EXPLAIN a self-join-free aggregate vs a correlated subquery version. Q47 EXPLAIN a LEFT JOIN anti-join (IS NULL). Q48 EXPLAIN (FORMAT JSON) a simple filter query. Q49 EXPLAIN a query ordering by a non-indexed expression. Q50 EXPLAIN ANALYZE a query and read off estimated vs actual rows. READ THE PLAN Q51 From a plan, state whether a Seq Scan or Index Scan was used and why. Q52 Identify the join algorithm in a 2-table join plan. Q53 Find the most expensive node (highest cost) in a plan. Q54 Find the node with the largest actual-time in EXPLAIN ANALYZE. Q55 Identify a large estimate-vs-actual row mismatch in a plan. Q56 Read off total estimated cost of a query. Q57 Identify whether a Sort spilled to disk (external merge) from the plan. Q58 Find "Rows Removed by Filter" and explain what it means. Q59 Identify a Nested Loop with a high loop count. Q60 Read "Heap Fetches" in an Index Only Scan. Q61 Determine if the query used the LIMIT to stop early (plan shows it). Q62 Identify a Bitmap Heap Scan + Bitmap Index Scan pair. Q63 From BUFFERS, tell cache hits from disk reads. Q64 Identify a Gather/parallel node in a plan. Q65 Explain what "loops=N" multiplies in a Nested Loop inner side. Q66 Identify the driving (outer) vs inner table in a Nested Loop. Q67 Read off the hash table memory usage in a Hash node. Q68 Spot a Materialize node and explain why it appeared. Q69 Tell whether ORDER BY was satisfied by an index or a Sort node. Q70 Identify aggregate node type (HashAggregate vs GroupAggregate). Q71 Determine if a subplan/SubPlan appears and what it represents. Q72 Read planning time vs execution time in EXPLAIN ANALYZE. Q73 Spot a Seq Scan on a big table that should have been filtered earlier. Q74 Compare two plans and say which is cheaper and why. Q75 Summarize a plan in one sentence ("scan -> filter -> sort -> limit"). SPOT THE SMELL (no index changes) Q76 Rewrite WHERE UPPER(email) = '[email protected] ' to a sargable form (lower on literal side or LIKE). Q77 Rewrite WHERE email LIKE '%@gmail.com' - why it can't use a plain B-tree; alternative. Q78 Replace SELECT * with only the needed columns in a wide-table query. Q79 Add a missing LIMIT to an exploration query on page_views. Q80 Rewrite WHERE EXTRACT(YEAR FROM order_date)=2025 to a sargable range. Q81 Rewrite OR across two columns as UNION ALL (and EXPLAIN both). Q82 Rewrite WHERE order_date::text LIKE '2025%' to a proper date range. Q83 Replace a correlated subquery with a JOIN and compare plans. Q84 Rewrite NOT IN (subquery with NULLs) as NOT EXISTS and compare. Q85 Rewrite WHERE price + 0 > 5000 to WHERE price > 5000 (drop the no-op math). Q86 Rewrite WHERE COALESCE(phone,'') = '' to an IS NULL/empty form. Q87 Show why SELECT DISTINCT to dedupe a join is a smell; suggest the fix. Q88 Rewrite a function-on-column ORDER BY into a plain-column ORDER BY where possible. Q89 Spot a cartesian product (missing join condition) in a plan. Q90 Rewrite WHERE substring(email,1,1)='a' to LIKE 'a%'. Q91 Identify SELECT * feeding a small LIMIT and trim the columns. Q92 Rewrite a leading-wildcard search to a prefix search where business allows. Q93 Spot an unfiltered join on a huge table and add the missing WHERE. Q94 Rewrite WHERE date_trunc('day',order_date)=DATE '2025-03-01' to a range. Q95 Replace an IN (long literal list) with a VALUES join and compare. Q96 Identify a missing LIMIT causing a full sort; add it. Q97 Rewrite WHERE cast(cust_id AS text)='123' to WHERE cust_id=123. Q98 Spot redundant ORDER BY in a subquery and remove it. Q99 Rewrite an aggregate-then-filter that should be a WHERE-then-aggregate. Q100 Given a slow plan, list 3 analyst-level rewrites (no index changes) to try first. Combined ideas, multi-step thinking
CONCEPTUAL Q1 How do you decide a plan is "bad" from EXPLAIN ANALYZE? Q2 Why does a wrong row estimate cascade into a bad join choice? Q3 When does the planner prefer Hash Join over Nested Loop? Q4 When is a Merge Join chosen, and what does it need (sorted inputs)? Q5 What makes a Sort spill to disk, and how does the plan show it? Q6 What does "Batches > 1" in a Hash node mean? Q7 Why does a leading-wildcard LIKE force a Seq Scan? Q8 Why is function-on-column non-sargable; give the general fix. Q9 What is "Rows Removed by Filter" telling you about selectivity? Q10 How does LIMIT change the chosen plan (early stop)? Q11 Why can OR across columns be slower than UNION ALL? Q12 Why does SELECT * prevent an Index Only Scan? Q13 What does a high loop count on a Nested Loop inner side imply? Q14 Estimated vs actual: which side (over/under) causes nested-loop blowups? Q15 Why might ANALYZE (stats refresh) fix a bad plan with no query change? Q16 How do BUFFERS hits vs reads indicate caching behavior? Q17 What is a Bitmap scan's sweet spot (selectivity range)? Q18 Why is "SELECT DISTINCT" to fix a fan-out join a smell? Q19 How does a correlated subquery appear in a plan (SubPlan/loops)? Q20 Why prefer EXISTS over IN when the subquery may return NULLs? Q21 What does GroupAggregate vs HashAggregate tell you about sorting? Q22 How does parallelism (Gather) show up and when does it help? Q23 Why is planning time relevant for very simple, frequently-run queries? Q24 How to compare two plans fairly (same warm cache, EXPLAIN ANALYZE)? Q25 What 3 things do you check first on any slow analyst query? DIAGNOSE THE BOTTLENECK Q26 EXPLAIN ANALYZE a customer-lifetime-spend aggregate; name the slow node. Q27 EXPLAIN ANALYZE the orders->customers join; Hash or Nested Loop? Q28 EXPLAIN ANALYZE a top-10 orders by net_total; did LIMIT help? Q29 EXPLAIN ANALYZE WHERE email LIKE '%gmail.com'; identify the Seq Scan. Q30 EXPLAIN ANALYZE a 3-table join; find the dominant node. Q31 EXPLAIN ANALYZE a GROUP BY with HAVING; HashAggregate or GroupAggregate? Q32 EXPLAIN ANALYZE an ORDER BY on a non-indexed column; did Sort spill? Q33 EXPLAIN ANALYZE a correlated subquery over orders; note loop count. Q34 EXPLAIN ANALYZE the equivalent JOIN; compare to Q33. Q35 EXPLAIN ANALYZE a query with a big estimate/actual mismatch; quantify it. Q36 EXPLAIN (ANALYZE,BUFFERS) a page_views scan; reads vs hits. Q37 EXPLAIN ANALYZE a DISTINCT over a fan-out join; spot the inflation. Q38 EXPLAIN ANALYZE a date-range filter; Index/Bitmap/Seq? Q39 EXPLAIN ANALYZE a NOT IN with a nullable subquery; behavior. Q40 EXPLAIN ANALYZE a self-join-free vs correlated "above-avg" query. Q41 EXPLAIN ANALYZE a query joining reviews->products->brand; bottleneck. Q42 EXPLAIN ANALYZE a wide SELECT * on orders vs trimmed columns. Q43 EXPLAIN ANALYZE an OR-across-columns filter; note the scan. Q44 EXPLAIN ANALYZE the UNION ALL rewrite of Q43; compare. Q45 EXPLAIN ANALYZE a HAVING-without-WHERE that should pre-filter. Q46 EXPLAIN ANALYZE a GROUP BY high-cardinality column; memory use. Q47 EXPLAIN ANALYZE a join missing a condition (accidental cross join). Q48 EXPLAIN ANALYZE a query with function-on-column in WHERE. Q49 EXPLAIN ANALYZE the sargable rewrite of Q48; compare. Q50 EXPLAIN ANALYZE a paginated OFFSET 100000 LIMIT 50; cost of deep offset. REWRITE FOR SARGABILITY Q51 Rewrite WHERE UPPER(email)=... to a sargable predicate. Q52 Rewrite WHERE EXTRACT(YEAR FROM order_date)=2025 to a half-open range. Q53 Rewrite WHERE date_trunc('month',order_date)=DATE '2025-03-01' to a range. Q54 Rewrite WHERE order_date::text LIKE '2025-03%' to a range. Q55 Rewrite WHERE cast(cust_id AS text)='123' to integer equality. Q56 Rewrite WHERE price*1.0 > 5000 to drop the no-op cast. Q57 Rewrite WHERE substring(email FROM 1 FOR 1)='a' to LIKE 'a%'. Q58 Rewrite WHERE COALESCE(net_total,0) > 0 to a sargable form. Q59 Rewrite OR (status='A' OR status='B') to IN and compare plans. Q60 Rewrite OR across two different columns as UNION ALL. Q61 Rewrite NOT IN (nullable subquery) to NOT EXISTS. Q62 Rewrite a correlated "above brand average" subquery as a JOIN to a grouped CTE. Q63 Rewrite SELECT * + LIMIT to a trimmed column list. Q64 Rewrite a leading-wildcard contains-search to a prefix search. Q65 Rewrite WHERE age(now(),registration_date) > INTERVAL '1 year' to a date compare. Q66 Rewrite WHERE lower(city)='mumbai' to compare with the literal lowered. Q67 Rewrite IN (huge literal list) as a JOIN to a VALUES table. Q68 Rewrite a self-join "previous order" into LAG (Topic 18) and compare plans. Q69 Rewrite WHERE net_total/quantity > 100 to avoid per-row division where possible. Q70 Rewrite a HAVING filter that belongs in WHERE (pre-aggregation). Q71 Rewrite DISTINCT-to-dedup-join using EXISTS instead. Q72 Rewrite WHERE order_date BETWEEN x AND y (inclusive) to half-open. Q73 Rewrite an ORDER BY random() sample to TABLESAMPLE. Q74 Rewrite a deep OFFSET pagination to keyset (Topic 5). Q75 Rewrite WHERE concat(first_name,last_name) ILIKE '%x%' to per-column predicates. JOIN & SORT TUNING (read/rewrite only) Q76 Compare plans of correlated-subquery vs JOIN for "customers above avg spend". Q77 Identify which table drives a Nested Loop and whether that's sensible. Q78 Pre-aggregate one side of a join in a CTE to cut fan-out; compare plans. Q79 Show how filtering before joining changes the plan (push WHERE down). Q80 Compare INNER JOIN vs EXISTS for "orders that have items". Q81 Compare LEFT JOIN ... IS NULL vs NOT EXISTS for anti-join. Q82 Identify a Sort that exists only to satisfy DISTINCT; rethink. Q83 Compare GROUP BY then JOIN vs JOIN then GROUP BY for an aggregate report. Q84 Show a Hash Join spilling (Batches>1) on a big aggregate; note it. Q85 Compare a 3-table join in two join orders (rewrite FROM order). Q86 Identify Materialize on the inner side and explain its role. Q87 Replace a redundant ORDER BY inside a subquery; show plan change. Q88 Compare DISTINCT vs GROUP BY for deduplication plans. Q89 Show how adding LIMIT lets a Nested Loop short-circuit. Q90 Compare UNION vs UNION ALL plans (dedupe cost). Q91 Identify an accidental cross join and add the join key. Q92 Compare IN (subquery) vs JOIN for "orders by top customers". Q93 Show the plan effect of selecting fewer columns (Index Only Scan eligibility). Q94 Compare correlated EXISTS vs semi-join rewrite plans. Q95 Identify a GroupAggregate forced by ORDER BY; could HashAggregate work? Q96 Compare a window-function top-N (Topic 16) vs correlated top-N plans. Q97 Show how a CTE materialization barrier changes a plan (MATERIALIZED hint). Q98 Compare aggregating in SQL vs returning rows for the BI tool (row counts). Q99 Identify the single most expensive node across a 4-table report and propose a rewrite. Q100 Given a slow 4-table analyst report, produce a prioritized rewrite plan (no indexes). Interview grade, edge cases
CONCEPTUAL Q1 Walk a methodical process for diagnosing a slow query from EXPLAIN ANALYZE. Q2 How do estimate errors propagate and cause Nested Loop blowups? Q3 BUFFERS: shared hit/read/dirtied - what each implies for I/O. Q4 When is a Seq Scan actually optimal (full aggregate, low selectivity)? Q5 How do you tell a Sort or Hash spilled to disk, and the work_mem link? Q6 Why is "actual rows x loops" the true work of an inner node? Q7 How does a missing/stale ANALYZE produce a bad plan? Q8 Identify a query where parallelism helps vs where it doesn't. Q9 Why can adding LIMIT dramatically change the chosen plan? Q10 How to compare two plans fairly (cache warmth, ANALYZE, repetition). Q11 What plan signs suggest "an index would help here"? Q12 What plan signs suggest indexing will NOT help? Q13 How does selectivity decide Index vs Bitmap vs Seq? Q14 Why does SELECT * block Index Only Scans? Q15 How does join order interact with the planner's reordering limit? Q16 What is a "row estimate of 1" trap that triggers Nested Loops? Q17 Why might a CTE act as an optimization fence (and PG12+ inlining)? Q18 How do you read NestedLoop + Materialize together? Q19 Why are leading-wildcard and function-on-column the top analyst smells? Q20 When is HashAggregate forced to spill, and the symptom in the plan? Q21 How to spot an accidental cross join from cost/row explosion. Q22 Why prefer rewriting before indexing for analyst ad-hoc queries? Q23 How does EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT JSON) aid tooling? Q24 What is plan regression and how do you catch it? Q25 Build a one-paragraph "tuning checklist" for analysts. PLAN FORENSICS Q26 SCENARIO: A customer-360 report is slow - EXPLAIN ANALYZE it and name the top-3 costly nodes. Q27 Find the node with the worst estimate/actual ratio in a 4-table report. Q28 From BUFFERS, decide if a query is I/O-bound or CPU-bound. Q29 Detect a Sort spilling to disk on a big ORDER BY; quantify. Q30 Detect a Hash Join with Batches>1; what would reduce it (no index)? Q31 Identify a Nested Loop with loops in the millions and explain the cause. Q32 Quantify "Rows Removed by Filter" and compute filter selectivity. Q33 Identify whether ORDER BY used an index or a Sort node. Q34 Find the planning-time vs execution-time split for a trivial query run often. Q35 Detect a Bitmap Heap Scan with high "exact heap blocks" vs "lossy". Q36 Identify a parallel plan and whether workers were actually launched. Q37 Detect a Materialize node and decide if it helped. Q38 From a JSON plan, extract the most expensive subtree programmatically (describe). Q39 Identify a SubPlan re-executed per row (correlated) and its cost. Q40 Detect a GroupAggregate forced by an upstream Sort. Q41 Identify a deep OFFSET causing a full scan+sort. Q42 Find a wide SELECT * preventing Index Only Scan; show row width impact. Q43 Detect a cartesian product from cost explosion in a multi-join. Q44 Compare warm vs cold cache runs (BUFFERS reads -> hits). Q45 Identify the join whose reorder would most help (largest intermediate). Q46 Detect an aggregate spilling (HashAggregate Disk Usage). Q47 From the plan, estimate the intermediate result size before the final aggregate. Q48 Identify whether a LIMIT short-circuited a Nested Loop early. Q49 Spot a redundant Sort that a prior operator already satisfied. Q50 Produce a ranked list of bottleneck nodes for a slow 5-table query. REWRITES THAT CHANGE THE PLAN Q51 Rewrite a correlated "above-average" query as a grouped JOIN; show plan win. Q52 Rewrite OR-across-columns as UNION ALL; quantify the improvement. Q53 Rewrite EXTRACT(YEAR ...) filter to a range; show Index/Bitmap appears. Q54 Rewrite NOT IN (nullable) to NOT EXISTS; correctness + plan. Q55 Rewrite SELECT * to needed columns to enable an Index Only Scan path. Q56 Rewrite deep OFFSET to keyset; show constant-time plan. Q57 Rewrite a fan-out DISTINCT into EXISTS; show row reduction. Q58 Pre-aggregate one side in a CTE to cut a Nested Loop blowup. Q59 Push a WHERE below a join (rewrite) to shrink intermediates. Q60 Replace ORDER BY random() LIMIT with TABLESAMPLE; plan diff. Q61 Rewrite IN (huge list) as a VALUES join; plan diff. Q62 Rewrite a self-join "previous value" into LAG; plan diff. Q63 Rewrite leading-wildcard search to prefix (where business allows). Q64 Rewrite a HAVING-only filter into WHERE; show pre-aggregation savings. Q65 Split an OR into two indexed-friendly branches via UNION ALL. Q66 Rewrite a date::text LIKE filter to a range; plan diff. Q67 Replace a multi-column concat ILIKE with per-column predicates. Q68 Rewrite correlated EXISTS to a semi-join; compare. Q69 Rewrite an aggregate over a join to aggregate-then-join; compare. Q70 Materialize a reused subquery via a CTE; measure. Q71 Convert a scalar correlated subquery in SELECT to a LEFT JOIN aggregate. Q72 Rewrite COUNT(DISTINCT x) heavy query into a two-step group; compare. Q73 Rewrite a window top-N vs correlated top-N and pick the better plan. Q74 Trim projected columns flowing into a sort to shrink memory. Q75 Produce before/after EXPLAIN ANALYZE for the biggest available win. "WOULD AN INDEX HELP?" (diagnosis only - fix is Topic 20) Q76 SCENARIO: A point-lookup by email is slow - diagnose whether an index would help (don't create it). Q77 Decide if a date-range orders query would benefit from an index. Q78 Decide if a full-table SUM(net_total) would benefit from an index (it won't - why). Q79 Identify the best candidate column(s) for a composite index from a 2-predicate query. Q80 Decide if a partial index (WHERE status='Cancelled') is justified by selectivity. Q81 Decide whether ORDER BY net_total DESC LIMIT 10 would benefit from an index. Q82 Decide if a leading-wildcard search needs a trigram index (Topic 20/extension). Q83 Decide if an expression index on lower(email) is warranted. Q84 Identify a redundant-index situation (describe; don't change). Q85 Decide if a join key lacks an index causing a Hash/Seq pattern. Q86 Decide if a low-selectivity predicate makes indexing pointless. Q87 Estimate the rows an index would have to return to be worthwhile. Q88 Decide if covering columns (INCLUDE) would enable Index Only Scan. Q89 Decide between single-column vs composite for a (cust_id, order_date) filter. Q90 Decide if a BRIN index suits the append-only page_views timestamp (concept). Q91 Decide if indexing helps a GROUP BY high-cardinality key (usually not). Q92 Decide if a foreign-key column needs an index for join performance. Q93 Identify which of 3 slow queries is the best indexing candidate. Q94 Decide if statistics (ANALYZE / extended stats) fix the plan instead of an index. Q95 Decide if the query should be rewritten before considering any index. Q96 Estimate index size/write-cost tradeoff for a hot write table (concept). Q97 Decide if a partial+covering index is the right tool for an "active rows" query. Q98 Rank 5 queries by expected index ROI (diagnosis). Q99 Write the Day-20 "to-do" index recommendation for a slow report (don't run it). Q100 Produce a full tuning report: bottleneck, rewrites tried, and index recommendations for Topic 20. Production scenarios, optimisation
CONCEPTUAL Q1 Explain the full lifecycle: parse -> plan (cost model) -> execute, and where EXPLAIN sits. Q2 How do the cost constants (seq_page_cost, random_page_cost, cpu_*) shape plan choice? Q3 effective_cache_size and its effect on index-vs-seq decisions. Q4 How estimate errors compound across a 5-table join. Q5 join_collapse_limit / from_collapse_limit and large-join planning. Q6 When does the planner stop reordering joins, and how to influence it. Q7 work_mem per-node semantics; total memory = nodes x work_mem x parallelism. Q8 Hash spill (batches) vs Sort spill (external merge) - diagnosis and levers. Q9 Parallel query: when Gather/Gather Merge helps; parallel-unsafe blockers. Q10 Genetic Query Optimizer (GEQO) for very large joins - implications. Q11 Extended statistics (CREATE STATISTICS) for correlated columns - when needed. Q12 Why row-estimate skew on a FK join causes nested-loop catastrophes. Q13 Plan stability: why the "same" query can flip plans over time. Q14 CTE materialization fence vs inlining (PG12+) and forcing each. Q15 Index Only Scan requirements (covering + visibility map). Q16 Bitmap AND/OR combining multiple indexes - when the planner does it. Q17 LATERAL for top-N-per-group vs window - plan tradeoffs. Q18 Partition pruning in plans (if partitioned) - what to look for. Q19 Why a tiny LIMIT can pick a wildly different (sometimes worse) plan. Q20 Auto-explain / pg_stat_statements for catching slow queries (concept; not installed here). Q21 Reading parallel-aware vs parallel-restricted nodes. Q22 Cost vs actual divergence: planner model limits to be aware of. Q23 When to push work to a materialized view (Topic 25) vs tune the query. Q24 Designing a repeatable benchmark for plan comparison. Q25 A staff-level mental model: read a plan in 60 seconds - the algorithm. MULTI-JOIN FORENSICS Q26 SCENARIO: A 6-table BI dashboard query times out - isolate the single worst node. Q27 Find the join whose intermediate result explodes and why (estimate error). Q28 Diagnose a Nested Loop chosen on a bad rows=1 estimate. Q29 Diagnose a Hash Join spilling across many batches on a big aggregate. Q30 Find where a Sort dominates and whether an upstream order could remove it. Q31 Identify a correlated SubPlan executed millions of times. Q32 Detect a cartesian product hidden in a 5-table FROM list. Q33 Quantify estimate/actual skew at each join level. Q34 Find the projection (SELECT *) inflating row width through the whole plan. Q35 Identify the parallelism gain (or lack) on a large scan. Q36 Detect a Materialize that should be a hash, or vice versa. Q37 Trace BUFFERS through the plan to find the I/O hotspot. Q38 Identify which FK join lacks support causing repeated scans. Q39 Find a GroupAggregate forced by a Sort that an index could remove (diagnose). Q40 Detect a deep OFFSET in a paginated report killing performance. Q41 Identify a DISTINCT masking a join fan-out and the true cause. Q42 Find the most expensive subtree in a JSON plan and summarize it. Q43 Diagnose a window-function sort dominating a report. Q44 Identify a HAVING that should be a WHERE pre-aggregation. Q45 Detect repeated computation that a CTE would materialize once. Q46 Find the join order the planner chose and propose a better one (rewrite FROM). Q47 Detect an aggregate spilling and estimate the memory needed. Q48 Identify a parallel-restricted function blocking parallelism. Q49 Compare the plan with/without a LIMIT to expose plan flips. Q50 Produce a ranked bottleneck report for the 6-table dashboard. PLAN STABILITY & REGRESSION Q51 SCENARIO: A nightly report got 10x slower with no code change - hypothesize causes from the plan. Q52 Show how stale statistics flip an Index Scan to a Seq Scan. Q53 Demonstrate ANALYZE restoring a good plan (run ANALYZE, re-EXPLAIN). Q54 Show how data growth changes selectivity and the chosen join. Q55 Show how a parameter value (generic vs custom plan) changes the plan. Q56 Demonstrate LIMIT-induced plan instability. Q57 Show extended statistics fixing a correlated-column estimate (concept + diagnose). Q58 Compare warm vs cold cache to avoid false regressions (BUFFERS). Q59 Identify a plan that's fast on small partitions but bad overall. Q60 Show CTE inlining (PG12+) changing a plan vs MATERIALIZED. Q61 Demonstrate how ORDER BY + LIMIT picks a different index path. Q62 Show how join_collapse_limit affects a many-table plan. Q63 Identify a regression from a row-estimate cliff at a boundary value. Q64 Show how work_mem changes a Sort from in-memory to disk. Q65 Build a minimal repro to compare two plans deterministically. Q66 Detect parameter-sniffing-style instability (custom vs generic plan). Q67 Show a plan that regresses only at month-end data volumes. Q68 Identify a function-volatility change forcing re-evaluation. Q69 Demonstrate that adding columns to SELECT removed an Index Only Scan. Q70 Show how a new low-cardinality value skews MCV-based estimates. Q71 Compare plans across two date ranges with very different selectivity. Q72 Detect a plan relying on an assumption that breaks as data evolves. Q73 Establish a "good plan" baseline to detect future regressions. Q74 Show how disabling a plan node (enable_seqscan=off, session) reveals alternatives. Q75 Write a regression-watch note: query, baseline plan, triggers to watch. END-TO-END TUNING METHODOLOGY Q76 SCENARIO: Own the company revenue dashboard - produce a full tuning report (diagnose->rewrite->index rec for Topic 20). Q77 Step 1: capture EXPLAIN (ANALYZE,BUFFERS) and identify the top bottleneck. Q78 Step 2: apply the highest-ROI rewrite and re-measure. Q79 Step 3: refresh statistics and re-check the plan. Q80 Step 4: list index recommendations (for Topic 20) with justification. Q81 Step 5: decide what belongs in a materialized view (Topic 25). Q82 Tune the customer-360 query end-to-end (rewrites only). Q83 Tune a cohort-retention query's plan (rewrites only). Q84 Tune a "top products per category" report (window vs LATERAL choice). Q85 Tune a monthly P&L report (pre-aggregation + push-down). Q86 Tune a funnel query's plan (rewrites only). Q87 Tune an RFM scoring query's plan. Q88 Tune a slow search query (leading wildcard) - diagnose trigram need (Topic 20). Q89 Tune a deep-pagination listing to keyset. Q90 Tune a COUNT(DISTINCT) heavy KPI query. Q91 Tune a self-join-based "previous order" to LAG. Q92 Tune an OR-heavy filter via UNION ALL. Q93 Tune an aggregate-over-join to aggregate-then-join. Q94 Decide MV vs query for an expensive nightly metric. Q95 Produce before/after metrics (time, BUFFERS) for one big win. Q96 Document the tuning so another analyst can reproduce it. Q97 Prioritize a backlog of 10 slow queries by expected ROI. Q98 Establish SLOs for dashboard query latency and how to monitor. Q99 Decide when to stop tuning (good enough) for an analyst workload. Q100 Deliver a one-page tuning playbook for the analytics team.