Course 6 of 6 · f1db, chinook, geoname, hashtag
Systematic bottleneck identification, query rewriting, index strategy, and verified improvements.
"The database feels slow" is not a starting point — it's a symptom without a location. Before anything is EXPLAINed, the first job is triaging pg_stat_statements into a ranked, reproducible list of what to fix first.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Reading EXPLAIN
select query,
calls,
round(total_exec_time::numeric, 1) as total_ms,
round(mean_exec_time::numeric, 1) as mean_ms,
round((100 * total_exec_time
/ sum(total_exec_time) over ())::numeric, 1)
as pct_total
from pg_stat_statements
order by total_exec_time desc
limit 10;Top 10 statement shapes ranked by cumulative execution time and share of total load.
An index gives the planner a new access path: instead of scanning every page, it can follow the B-tree straight to matching rows. This module covers every index type f1db, geoname, and hashtag put to use.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Indexing Strategy
-- This query scans all results to find
-- race winners — a partial index on
-- positionorder = 1 would eliminate it.
--
-- CREATE INDEX ON f1db.results (raceid)
-- WHERE positionorder = 1;
explain (analyze, buffers)
select res.raceid,
res.driverid,
res.constructorid
from f1db.results res
where res.positionorder = 1
order by res.raceid;Raceid, driverid, and constructorid for every race winner, ordered by raceid.
Small changes in SQL can have large performance impacts. The most effective rewrites work with the planner's cost model — reducing intermediate result sets and removing barriers it can't see through.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Query Rewriting & Anti-Patterns
-- Inline predicates give the planner freedom
-- to push them to the earliest scan.
explain (analyze, buffers)
select r.name, r.date,
d.surname as winner
from f1db.races r
join f1db.results res
on res.raceid = r.raceid
and res.positionorder = 1
join f1db.drivers d
on d.driverid = res.driverid
where r.year = 2017;Race names, dates, and 2017 winners with all predicates placed inline in the join.
Some slow queries are not exotic at all — they are the same handful of mistakes, written daily in every codebase. Each one has a recognizable EXPLAIN signature and a mechanical fix.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Query Rewriting & Anti-Patterns
-- Keyset: seek straight to the last key seen.
-- The B-tree descends once and reads exactly
-- one page of rows — page 5000 costs the
-- same as page 1.
explain (analyze, buffers)
select geonameid, name
from geoname.geoname
where geonameid > 10150618
order by geonameid
limit 20;Twenty geoname rows starting after a known geonameid boundary, ordered by geonameid.
Every planner estimate assumes columns are independent unless told otherwise — selectivity(a=1 AND b=2) is computed as if knowing one told you nothing about the other. CREATE STATISTICS fixes that.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Reading EXPLAIN
-- geoname.class and .feature are strongly
-- correlated: 'PPL' always implies class 'P'.
-- The planner multiplies selectivities as
-- if they were independent and lands far
-- below the actual row count.
--
-- create statistics geoname_class_feature
-- (dependencies) on class, feature
-- from geoname.geoname;
explain (analyze, buffers)
select name, population
from geoname.geoname
where class = 'P'
and feature = 'PPL';EXPLAIN ANALYZE plan for geoname rows matching both class 'P' and feature 'PPL'.
Indexes, rewrites, and statistics change what the planner knows and what access paths exist. Configuration changes what the planner believes about the hardware itself — memory, cost, and parallelism settings.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Indexing Strategy
select name,
setting,
unit,
short_desc
from pg_settings
where name in (
'work_mem',
'effective_cache_size',
'random_page_cost',
'seq_page_cost',
'max_parallel_workers_per_gather'
)
order by name;Name, setting, unit, and description for five memory, cost, and parallelism parameters.
By this point you have a diagnosis and a full toolbox — indexes, rewrites, extended statistics, configuration. This module is the discipline that turns fixes into verified, monitored improvements.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Reading EXPLAIN · Query Rewriting & Anti-Patterns · Indexing Strategy
-- Step 1: capture the default plan and cost.
-- Step 2: apply one fix, then compare actual
-- time against the captured baseline.
explain (analyze, buffers)
select d.surname,
sum(res.points) as points
from f1db.results res
join f1db.drivers d
on d.driverid = res.driverid
group by d.driverid, d.surname
order by points desc
limit 10;Total career points per driver ranked descending, limited to the top 10.
At scale, query optimization becomes part of system design. Partitioning strategy, parallelism, materialized views, and denormalization determine whether individual query fixes hold up under load.
Book reference: Chapter 9 — Indexing Strategy
Free preview: Reading EXPLAIN · Query Rewriting & Anti-Patterns · Indexing Strategy
select parent.relname as parent_table,
child.relname as partition_name,
pg_size_pretty(
pg_relation_size(child.oid)
) as partition_size
from pg_inherits
join pg_class parent
on parent.oid = pg_inherits.inhparent
join pg_class child
on child.oid = pg_inherits.inhrelid
join pg_namespace n
on n.oid = parent.relnamespace
where n.nspname = 'f1db'
order by parent.relname, child.relname;Every f1db partition's name and physical size, grouped by parent table.
Core, Advanced, and Architect tiers — 48 modules across 6 PostgreSQL courses.