Skip to main content

pg-advisor

PostgreSQL schema & query advisor — rule-based, no AI, fully deterministic.

Connect your database, and it will tell you what's wrong and how to fix it.

╭──────────────────────────── pg-advisor Report ────────────────────────────╮
│ localhost/mydb                                                             │
│ ❌ 3 critical  ⚠  4 warnings  ℹ  5 info  (12 total)                       │
╰────────────────────────────────────────────────────────────────────────────╯

━━━ Table: orders ━━━
  ❌ CRITICAL  FK_WITHOUT_INDEX.user_id
    'orders.user_id' has a foreign key to 'users' but no index — JOINs will be slow.
    → CREATE INDEX idx_orders_user_id ON orders(user_id);

  ❌ CRITICAL  FLOAT_FOR_MONEY.total
    'orders.total' uses FLOAT type — precision errors may occur.
    → ALTER TABLE orders ALTER COLUMN total TYPE NUMERIC(12,2);

  ⚠  WARNING   DUPLICATE_INDEX
    2 indexes exist for columns ['total'] — one is redundant.
    → DROP INDEX idx_orders_total2;

Install

pip install pg-advisor

Quick Start

Run this after installing to check your PostgreSQL extension setup:

pg-advisor setup postgresql://user:pass@localhost:5432/mydb

Then run the full analysis:

pg-advisor analyze postgresql://user:pass@localhost:5432/mydb

Extension Setup

pg-advisor uses three PostgreSQL extensions. Run pg-advisor setup to check which ones are available on your database.

Extension Type Used for Required?
pg_stat_activity Built-in Live query monitoring, lock waits, connection pool Auto-available
pg_stat_statements Built-in, off by default Slow queries, SELECT * detection, high-frequency queries Optional
hypopg Third-party Confirms an index will actually improve query cost Optional

Missing extensions are skipped gracefully — pg-advisor will still run and report all other issues.

Enabling pg_stat_statements

-- 1. Add to postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'

-- 2. Restart PostgreSQL, then run in your database:
CREATE EXTENSION pg_stat_statements;

Installing hypopg

# Ubuntu / Debian
sudo apt install postgresql-<version>-hypopg

# macOS (Homebrew)
brew install hypopg
-- Then in your database:
CREATE EXTENSION hypopg;

Usage

Option 1 — Direct URL:

pg-advisor analyze postgresql://user:pass@localhost:5432/mydb

Option 2 — Environment variable:

export DATABASE_URL=postgresql://user:pass@localhost/mydb
pg-advisor analyze

Option 3 — .env file:

DATABASE_URL=postgresql://user:pass@localhost/mydb
pg-advisor analyze

Scan model files too (SQLAlchemy / Django / SQL):

pg-advisor analyze --models-path ./models/
pg-advisor analyze --models-path .        # scan entire project

Skip specific checks:

pg-advisor analyze --skip-queries     # skip pg_stat_statements checks
pg-advisor analyze --skip-hypopg      # skip hypothetical index testing
pg-advisor analyze --skip-activity    # skip live connection monitoring

Output & Reports

After every run, pg-advisor prints a colored summary to the terminal. It then prompts you to save a Markdown report:

──────────────────────────────────────────────────
  Save Markdown (.md) report? (yes/no):

Answer yes and the file is written immediately:

  ✅ Report saved at: /your/project/pgadvisor_report/pg_advisor_report_20260408_143022.md

Skip the prompt with flags:

pg-advisor analyze ... --save-report   # always save, no prompt
pg-advisor analyze ... --no-report     # never save, no prompt (CI/CD)

Report folder & file naming

Detail Value
Folder pgadvisor_report/ — auto-created in your current working directory on first run
Filename pg_advisor_report_YYYYMMDD_HHMMSS.md
Example pgadvisor_report/pg_advisor_report_20260408_143022.md
Encoding UTF-8

The folder is created automatically — no setup needed. Each run produces a uniquely timestamped file; existing reports are never overwritten.

What the Markdown report contains

  • Summary header — database, timestamp, critical / warning / info counts
  • Issue summary table — every issue across all tables in one place
  • Per-table sections — each issue with severity, message, and a ready-to-run SQL fix block
  • Rule reference — full list of all rules and what they check

What does it check?

Schema Rules

Rule What it detects Severity
MISSING_PK Table without primary key ❌ Critical
FLOAT_FOR_MONEY price, balance, total columns using FLOAT type ❌ Critical
FK_WITHOUT_INDEX No index on foreign key column ❌ Critical
NULLABLE_PK Primary key marked as nullable ❌ Critical
MISSING_CREATED_AT created_at column is missing ⚠ Warning
BOOL_AS_INT is_active, has_access stored as INTEGER ⚠ Warning
GOD_TABLE Table with 30+ columns — consider splitting ⚠ Warning
MISSING_NOT_NULL Email, name, status columns are nullable ℹ Info
MISSING_UPDATED_AT updated_at column is missing ℹ Info

Index Rules

Rule What it detects Severity
DUPLICATE_INDEX 2+ indexes on the same columns ⚠ Warning
UNUSED_INDEX Index never used (detected from live DB) ⚠ Warning
LOW_CARDINALITY_INDEX Index on boolean/status column ℹ Info

Query Rules (requires pg_stat_statements)

Rule What it detects Severity
SLOW_QUERY Average execution time ≥ 500ms ❌ Critical
HIGH_FREQUENCY_QUERY 1000+ calls — consider caching ⚠ Warning
SELECT_STAR Use of SELECT * in queries ⚠ Warning

Activity Rules (pg_stat_activity — built-in)

Rule What it detects Severity
LONG_RUNNING_QUERY Query running for 30s+ ❌ Critical
IDLE_IN_TRANSACTION Connection idle-in-transaction for 60s+ ❌ Critical
LOCK_WAIT Query blocked waiting for a lock ❌ Critical
CONNECTION_POOL_PRESSURE 80%+ of max_connections in use ⚠ Warning

Hypothetical Index Rules (requires hypopg)

Rule What it detects Severity
HYPOPG_INDEX_CONFIRMED Index verified to reduce query cost ❌ Critical

Model File Scanning

Can detect issues from model files without connecting to the database:

SQLAlchemy:

class Order(Base):
    __tablename__ = "orders"
    total = Column(Float)        # ← will flag FLOAT_FOR_MONEY

Django ORM:

class Order(models.Model):
    total = models.FloatField()  # ← same flag

Plain SQL:

CREATE TABLE orders (
    total FLOAT                  -- ← same flag
);

Project Structure

pg_advisor/
├── connectors/
│   └── postgres.py          # DB connection, URL resolver
├── collectors/
│   ├── db_schema.py         # Fetch schema from live DB
│   └── model_scanner.py     # Scan SQLAlchemy/Django/SQL files
├── analyzers/
│   ├── schema_rules.py      # Schema issues (9 rules)
│   ├── index_rules.py       # Index issues (3 rules)
│   ├── query_rules.py       # Query issues (3 rules)
│   ├── activity_rules.py    # Live monitoring (4 rules)
│   └── hypopg_rules.py      # Hypothetical index testing (1 rule)
├── reporters/
│   ├── cli_reporter.py      # Colored terminal output
│   └── md_reporter.py       # Markdown report generator
└── cli.py                   # Entry point

Requirements

  • Python 3.11+
  • PostgreSQL 12+
  • psycopg2-binary, rich, python-dotenv (auto-installed via pip)

License

MIT

Release files for pg-advisor 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pg-advisor 0.2.0
File Size Uploaded
pg_advisor-0.2.0.tar.gz 30.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pg-advisor 0.2.0
File Interpreter ABI Platform
pg_advisor-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 64.6 kB

Release files / pg_advisor-0.2.0.tar.gz

Download URL pg_advisor-0.2.0.tar.gz
Size 30.7 kB
Tags Source
SHA-256 checksum
How to use checksums
a622ee3e67dc750106137ee6d9c5b2fec13723024cffcbf6c3b180779719b9b5
BLAKE2b-256 checksum
How to use checksums
399621e04744c23eebb5f1d4db4433be674e72407e3c1631dbafac2cb9c78c8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / pg_advisor-0.2.0-py3-none-any.whl

Download URL pg_advisor-0.2.0-py3-none-any.whl
Size 33.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8e497063053c2da35bd3adfbb6208c12b976d4f3675a015ba93f2b9d822f9b4d
BLAKE2b-256 checksum
How to use checksums
ef6dd8bdde87d469525fce2baaa02a78e23e39c7bd3f97b14c664331dcd47581
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page