Database Performance

PostgreSQL Query Planner Hints: pg_hint_plan and Statistics Tuning

Guide the PostgreSQL query planner with enable_xxx settings, pg_hint_plan extension, and extended statistics for correlated columns. Fix bad plans without rewriting queries.

JusDB Team
August 18, 2025
Updated June 20, 2026
5 min read

PostgreSQL's query planner is excellent but occasionally chooses a suboptimal plan. Unlike MySQL, PostgreSQL has no native query hints — but several tools and techniques let you guide or force the planner.

Disable Specific Plan Nodes

sql
-- Force sequential scan (disable index scans)
SET enable_indexscan = off;
SET enable_bitmapscan = off;

-- Force nested loop (disable hash join)
SET enable_hashjoin = off;
SET enable_mergejoin = off;

-- Re-enable after your query
SET enable_indexscan = on;
SET enable_hashjoin = on;
Warning: These settings affect ALL queries in the session. Use SET LOCAL inside a transaction to scope them to one query.

pg_hint_plan Extension

pg_hint_plan adds MySQL-style hint comments to PostgreSQL:

bash
# Install
apt-get install postgresql-15-pg-hint-plan

# Add to postgresql.conf:
# shared_preload_libraries = 'pg_hint_plan'
sql
-- Force index scan on orders table
/*+ IndexScan(orders idx_orders_created_at) */
SELECT * FROM orders WHERE created_at > '2025-01-01';

-- Force nested loop join
/*+ NestLoop(orders users) */
SELECT * FROM orders JOIN users ON orders.user_id = users.id
WHERE orders.status = 'pending';

-- Force specific join order
/*+ Leading(orders users products) */
SELECT * FROM orders
JOIN users ON ...
JOIN products ON ...;

Fix Bad Plans with Statistics

Before forcing plans, try improving planner statistics:

sql
-- Increase statistics target for poor-estimate columns
ALTER TABLE orders ALTER COLUMN status SET STATISTICS 500;
ANALYZE orders;

-- Check current estimate accuracy
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE status = 'pending';
-- Compare 'rows=X' (estimate) vs 'actual rows=Y' (reality)
-- Large discrepancy = bad statistics = planner chooses wrong plan

Correlated Column Statistics

sql
-- Create extended statistics for correlated columns
CREATE STATISTICS orders_stats (dependencies) ON status, region FROM orders;
ANALYZE orders;

-- Check extended statistics
SELECT * FROM pg_statistic_ext WHERE stxname = 'orders_stats';

Key Takeaways

  • Always fix statistics first — most bad plans come from stale or insufficient statistics
  • Use SET LOCAL enable_xxx = off inside a transaction to scope changes to one query
  • pg_hint_plan provides MySQL-style hints as SQL comments — useful for permanent hint application
  • Use extended statistics (CREATE STATISTICS) for correlated columns the planner misjudges

JusDB Can Help

Query planner issues can be subtle and hard to diagnose. JusDB specializes in PostgreSQL query plan optimization and statistics tuning.

Share this article

JusDB Team

Official JusDB content team

Keep reading

SQL Server Wait Stats: A Diagnostic Playbook for Slow Queries

Read SQL Server wait stats like a senior DBA: the four DMV sources, the eight wait types that cover 95% of incidents (PAGEIOLATCH, LCK_M, CXPACKET, WRITELOG…), and the remediation for each. A 30-minute diagnostic workflow from page to plan.

SQL Server12 minMay 27, 2026
Read

InnoDB Architecture Explained (2026): Buffer Pool, Redo Log & Production Tuning

Deep dive into InnoDB storage engine internals. Understand buffer pool, redo log, undo log, change buffer, and adaptive hash index for expert-level MySQL optimization.

MySQL16 minMay 13, 2026
Read

MySQL 8.4 Parallel DDL: innodb_parallel_read_threads & innodb_ddl_threads Tuning

Leverage MySQL 8.4 InnoDB parallel DDL for faster schema changes. Learn parallel index creation, online DDL improvements, and reduced maintenance windows.

MySQL8 minMay 13, 2026
Read