Skip to content
Back to skills

Postgres Pro

ASecurity

Deep PostgreSQL know-how — indexing, tuning, JSONB, and administration — use when working with or troubleshooting Postgres.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentsgosqlnodeexpressdatabase

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add aicodedecode/awesome-muse-skills --skill postgres-pro --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Postgres Pro?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Postgres Pro
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aicodedecode-postgres-pro/badge)](https://www.skillsdirectory.com/skills/aicodedecode-postgres-pro)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: postgres-pro
description: Deep PostgreSQL know-how — indexing, tuning, JSONB, and administration — use when working with or troubleshooting Postgres.
category: database
---

## Overview

PostgreSQL is a production workhorse: ACID-compliant, extensible, and generous with
features (JSONB, full-text search, arrays, PostGIS). This skill covers the
operational knowledge that separates a working Postgres setup from a reliable one:
choosing indexes, reading plans, tuning configuration, and safe administration.

## When to use

- Choosing between B-tree, GIN, GiST, BRIN, or hash indexes
- Investigating slow queries with `EXPLAIN (ANALYZE, BUFFERS)`
- Tuning `shared_buffers`, `work_mem`, `maintenance_work_mem`, autovacuum
- Designing schemas with JSONB, arrays, or full-text search
- Managing backups, replication, connections, and upgrades

## Core concepts

**Index types matter.** B-tree is the default and right for most lookups and range
queries. GIN powers JSONB containment (`@>`) and full-text search; GiST handles
geometric and range types; BRIN shines for very large, naturally ordered tables
(time-series). A GIN index on a JSONB column can turn a 10-second scan into a
10-millisecond lookup — but adds write overhead.

**MVCC and bloat.** Postgres never overwrites rows in place; updates create new
row versions and dead tuples are reclaimed by VACUUM. Long-running transactions
block cleanup and cause bloat. Monitor `pg_stat_user_tables` for tables where
`n_dead_tup` grows faster than autovacuum cleans.

**`EXPLAIN (ANALYZE, BUFFERS)` is ground truth.** It shows actual row counts,
timing per node, and buffer hits vs disk reads. Compare estimated vs actual rows:
a 100x misestimate usually means stale statistics (`ANALYZE`) or a bad plan forced
by them.

**Connection discipline.** Postgres uses a process per connection; thousands of
idle connections waste memory. Use a pooler (PgBouncer in transaction mode) in
front of the database and keep `max_connections` modest.

**JSONB done right.** Store flexible documents in `jsonb`, query with `->` / `->>`,
index hot paths with GIN or expression indexes. Don't use JSONB as an excuse to
skip schema design — frequently queried fields often deserve real columns.

## Practical workflow

1. **Diagnose with data:** `EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)` on the slow
   query; find the node consuming most time.
2. **Check the usual suspects:** missing index (Seq Scan on a large filtered
   table), stale stats (`ANALYZE table_name`), bloat (`pgstattuple`), lock waits
   (`pg_stat_activity`).
3. **Create indexes deliberately:** one composite index on `(filtered_col,
   ordered_col)` often beats two single-column indexes; use `CONCURRENTLY` in
   production to avoid locking the table:
   ```sql
   CREATE INDEX CONCURRENTLY idx_orders_customer_date
     ON orders (customer_id, order_date DESC);
   ```
4. **Tune conservatively:** start with `shared_buffers` ≈ 25% of RAM,
   `effective_cache_size` ≈ 75% of RAM, `work_mem` small (4–64MB) — raise only
   with evidence of sorts spilling to disk (`EXPLAIN` shows "Disk:" sorts).
5. **Backups before changes:** verify `pg_dump`/`pg_basebackup` restores actually
   work — an untested backup is not a backup. Test restores on a schedule.
6. **Safe migrations:** add columns as nullable (or with defaults via metadata-only
   changes in modern versions), backfill in batches, then add `NOT NULL` with
   `VALIDATE CONSTRAINT` to avoid long locks.

## Common pitfalls

- **Killing autovacuum or disabling it** — leads to bloat, transaction-ID wraparound
  risk, and eventually downtime. Tune it, don't disable it.
- **Creating indexes without `CONCURRENTLY`** on live tables — takes an
  `ACCESS EXCLUSIVE` lock and blocks writes.
- **Wrapping indexed columns in functions** in `WHERE` (e.g.
  `WHERE lower(email) = ...`) — defeats the index unless you create an expression
  index on `lower(email)`.
- **`SELECT ... FOR UPDATE` without ordering** — invites deadlocks under
  concurrency; lock rows in a consistent order.
- **Timezone bugs:** `timestamp without time zone` silently shifts meaning.
  Prefer `timestamptz` and convert at the presentation layer.
- **Running out of connections** under load — add pooling before raising
  `max_connections`; each connection costs real memory.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…