Skip to content

PostgreSQL Query Optimization: JIT & pg_stat_statements

CoreConceptAugust 6, 20264 min read

As database tables grow to tens of millions of rows, un-optimized PostgreSQL queries cause sudden CPU spikes, connection pool exhaustion, and elevated API tail latencies. Engineering teams often struggle to diagnose which specific SQL query shapes are consuming the majority of database CPU cycles and disk I/O bandwidth.

PostgreSQL Performance Tuning Utilities provide deep visibility into query execution internals. The pg_stat_statements extension tracks aggregate execution statistics (total time, call count, mean latency, buffer cache hits) for all normalized SQL queries. LLVM JIT (Just-In-Time) Compilation accelerates complex analytical queries by compiling expression evaluation and tuple de-deconstruction directly into machine code. This guide details pg_stat_statements analysis, LLVM JIT tuning thresholds, parallel query workers, and buffer cache hit ratio optimization.

PostgreSQL Query Optimization architecture comparison featuring pg_stat_statements metrics, LLVM JIT compilation, and parallel query execution workers
PostgreSQL Query Optimization architecture comparison featuring pg_stat_statements metrics, LLVM JIT compilation, and parallel query execution workers

Mental Model: Black-Box Database Slowness vs Internal Execution Statistics

Monitoring database server CPU metrics alone does not reveal which queries are responsible for performance bottlenecks:

1. Black-Box Metrics: High CPU or disk I/O indicates database stress but fails to identify offending SQL statements. 2. Internal Execution Statistics: Extension pg_stat_statements records query execution metrics per normalized SQL pattern, pinpointing queries with high total execution time or frequent cache misses. For table partitioning and query plan analysis, review postgres partitioning vs sharding and optimizing postgresql query performance explain analyze.

PostgreSQL query execution pipeline showing pg_stat_statements metrics tracking, LLVM JIT compilation check, and parallel worker gather output
PostgreSQL query execution pipeline showing pg_stat_statements metrics tracking, LLVM JIT compilation check, and parallel worker gather output

Quick reference

  • Normalizes SQL query constants to aggregate metrics per query pattern across application restarts.
  • Identifies top 5 queries consuming 80%+ of total database CPU and disk I/O runtime.
  • Measures shared_blks_hit vs shared_blks_read to compute exact buffer cache hit ratios.
  • Exposes lock wait times (shared_blks_dirtied, temp_blks_written) for concurrent query stalls.
  • Used for database performance diagnostics at Instagram, GitLab, Notion, Twitch, and CoreConcept.

Remember this

Enable pg_stat_statements to identify the top SQL queries causing database CPU and disk I/O bottlenecks.

Identifying Heavy SQL Queries via pg_stat_statements & pg_stat_activity

Enabling pg_stat_statements requires adding it to postgresql.conf under shared_preload_libraries:

1-- Query Top 5 Slowest Queries by Total Execution Time2SELECT 3  round(total_exec_time::numeric, 2) AS total_ms,4  calls,5  round(mean_exec_time::numeric, 2) AS avg_ms,6  round((100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0))::numeric, 2) AS hit_ratio,7  query8FROM pg_stat_statements9ORDER BY total_exec_time DESC10LIMIT 5;

Quick reference

  • total_exec_time identifies overall database load contribution across all calls.
  • mean_exec_time highlights individual slow query outliers requiring index optimization.
  • Low hit_ratio (<99%) indicates queries reading heavily from physical disk instead of RAM buffer cache.
  • pg_stat_activity displays active real-time queries currently executing on backend worker PIDs.
  • Reset statistics periodically via SELECT pg_stat_statements_reset() after deploying optimizations.

Remember this

Analyze total_exec_time and buffer hit_ratio in pg_stat_statements to prioritize SQL query tuning.

LLVM JIT Compilation Thresholds (jit_above_cost, jit_inline_above_cost)

PostgreSQL 11+ incorporates LLVM JIT Compilation to speed up expression evaluation in complex WHERE clauses and aggregates (SUM, AVG):

- JIT Compilation Cost Thresholds: JIT compilation adds a short upfront compilation overhead (~10ms - 50ms). For short OLTP queries (<5ms), JIT compilation increases total query latency. For heavy OLAP queries (>1000ms), JIT compilation yields a 2x - 5x execution speedup:

1# postgresql.conf JIT Threshold Tuning2jit = on3jit_above_cost = 100000        # Compile query if estimated cost > 100k4jit_inline_above_cost = 500000 # Inline functions if cost > 500k5jit_optimize_above_cost = 500000
PostgreSQL query execution pipeline showing pg_stat_statements metrics tracking, LLVM JIT compilation check, and parallel worker gather output
PostgreSQL query execution pipeline showing pg_stat_statements metrics tracking, LLVM JIT compilation check, and parallel worker gather output

Quick reference

  • LLVM JIT compiles WHERE expressions and aggregate functions into native machine code.
  • Substantially accelerates CPU-bound analytical queries over large tables.
  • High jit_above_cost thresholds prevent JIT compilation overhead on fast OLTP queries.
  • EXPLAIN ANALYZE displays JIT compilation time, inline functions, and optimization duration.
  • Optimizes CPU cycle utilization for analytical data reporting workflows.

Remember this

Tune jit_above_cost thresholds to ensure LLVM JIT compiles heavy OLAP queries while bypassing fast OLTP lookups.

Parallel Query Execution Workers (max_parallel_workers_per_gather) & Index Tuning

PostgreSQL can parallelize sequential scans, hash joins, and aggregations across multiple CPU cores:

- Parallel Worker Settings: Setting max_parallel_workers_per_gather = 4 allows a single query leader process to spawn 4 parallel background worker processes to scan table pages simultaneously. - Covering Index Optimization: Creating INCLUDE indexes (CREATE INDEX idx_orders_user ON orders (user_id) INCLUDE (total_amount)) allows Index-Only Scans, completely bypassing table heap reads.

Quick reference

  • Parallel sequential scans distribute table page reads across multiple CPU cores.
  • max_worker_processes caps global parallel worker allocation across all active queries.
  • Covering indexes (INCLUDE clause) enable Index-Only Scans, eliminating table heap page fetches.
  • B-Tree index fillfactor tuning prevents page splitting on high-update tables.
  • Delivers sub-second query performance for enterprise PostgreSQL database clusters.

Remember this

Configure parallel query workers and covering indexes to accelerate sequential scans and eliminate heap reads.

Key takeaway

To test pg_stat_statements locally, run CREATE EXTENSION IF NOT EXISTS pg_stat_statements; in psql and inspect metrics via SELECT * FROM pg_stat_statements LIMIT 5;.

Share:

Related Articles

A selective lookup that once scanned most of a large table can become an index walk plus a few heap fetches — often the

Read

"The index exists, why is this query still slow?" is one of the most common database escalations — and the answer is alm

Read

At the heart of every database system lies a Storage Engine that determines how data is written to disk, indexed, and re

Read

Keep learning

Follow a structured path or browse all courses to go deeper.