Section 6: The Query Planner and EXPLAIN
- How the planner chooses a plan: statistics, cost and ANALYZE
- Read EXPLAIN (ANALYZE, BUFFERS) line by line to find where time goes
- Seq scans, index scans, bitmap scans and the different join methods
- Enable pg_stat_statements to find the queries with the highest total time
- Lab: track down slow queries in a sample app and measure before and after
Section 7: Lab: Designing Indexes That Match Your Queries
- Composite B-tree indexes and getting the column order right
- Partial, expression and covering indexes with INCLUDE
- B-tree skip scan in PostgreSQL 18 and what it changes for index design
- Choosing GIN, GiST or BRIN for the data type at hand
- Why an index is not used, and the cost of having too many indexes
Section 8: Transactions, MVCC and Locking
- How MVCC works and why VACUUM is needed
- Isolation levels: Read Committed, Repeatable Read and Serializable
- Row locks, SELECT ... FOR UPDATE and finding locks that are held too long
- What causes deadlocks and how to write code that avoids them
- Lab: build a job queue with FOR UPDATE SKIP LOCKED
Section 9: PL/pgSQL, Procedures and Triggers
- Write functions and procedures in PL/pgSQL with error handling
- Triggers for audit logs and keeping updated_at current
- SQL functions compared with PL/pgSQL, and function volatility
- Criteria for deciding which logic belongs in the database and which in the app
Section 10: Views, Materialized Views and Partitioning
- Views to hide complexity and limit what data is visible
- Materialized views and REFRESH ... CONCURRENTLY
- Declarative range and list partitioning for large tables
- Partition pruning and choosing a partition key that fits the queries
- Lab: partition a log table by month and test the result