# Code Reference — Postgres

_13 pages_

---
# Postgres (/docs/postgres)



# Postgres [#postgres]

Ops, indexes, backups, EXPLAIN.

Browse the sidebar for every cheat sheet in this section.

## Sections [#sections]

*All notes are listed in the sidebar.*


---

# Backups & Restore (/docs/postgres/backups-restore)



# Backups & Restore [#backups--restore]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Backups are only real if restores are rehearsed. Use logical dumps for portability and physical/base backups for large clusters and PITR with WAL archiving.

## 🔧 Core concepts [#-core-concepts]

| Method          | Tooling                   | Notes                           |
| --------------- | ------------------------- | ------------------------------- |
| Logical         | `pg_dump`, `pg_dumpall`   | Flexible, slower for huge DBs   |
| Logical restore | `psql`, `pg_restore`      | Custom format supports parallel |
| Physical        | `pg_basebackup`           | Cluster-level                   |
| PITR            | Base backup + WAL archive | Restore to timestamp            |

| Format    | Flag                    |
| --------- | ----------------------- |
| Plain SQL | `pg_dump` default       |
| Custom    | `-Fc` for `pg_restore`  |
| Directory | `-Fd` parallel friendly |

## 💡 Examples [#-examples]

**Dump one database:**

```shellscript
pg_dump -Fc -f app.dump "$DATABASE_URL"
```

**Restore custom format:**

```shellscript
pg_restore --clean --if-exists -d "$DATABASE_URL" app.dump
```

**SQL dump:**

```shellscript
pg_dump "$DATABASE_URL" > app.sql
psql "$DATABASE_URL" -f app.sql
```

## ⚠️ Pitfalls [#️-pitfalls]

* Untested backups fail when you need them — schedule restore drills.
* Dumping a live DB without awareness of long transactions can capture inconsistent app-level state (DB is consistent; apps may need quiesce).
* Restoring over production without a rename/canary is a career-limiting move.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/postgres/getting-started)
* [connect\_psql.md](/docs/postgres/connect-psql)
* [migrations\_ops.md](/docs/postgres/migrations-ops)
* [connection\_pooling.md](/docs/postgres/connection-pooling)


---

# Connect with psql (/docs/postgres/connect-psql)



# Connect with psql [#connect-with-psql]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`psql` is the primary admin CLI: run SQL, inspect catalogs with meta-commands, and script automation with variables and `\copy`.

## 🔧 Core concepts [#-core-concepts]

| Connection form | Example                                |
| --------------- | -------------------------------------- |
| URL             | `postgres://user:pass@host:5432/db`    |
| Flags           | `psql -h host -U user -d db`           |
| `.pgpass`       | Password file for non-interactive auth |
| `PG*` env       | `PGHOST`, `PGUSER`, `PGDATABASE`       |

| Meta-command | Purpose                 |
| ------------ | ----------------------- |
| `\l`         | List databases          |
| `\c db`      | Connect to db           |
| `\dt`        | List tables             |
| `\d table`   | Describe table          |
| `\du`        | List roles              |
| `\x`         | Expanded display toggle |
| `\timing`    | Show query time         |
| `\q`         | Quit                    |

## 💡 Examples [#-examples]

**Connect and list tables:**

```shellscript
psql -h 127.0.0.1 -U app -d app
```

```
\dt
\d users
```

**Run file / one-shot:**

```shellscript
psql "$DATABASE_URL" -f migrate.sql
psql "$DATABASE_URL" -c "SELECT now();"
```

**CSV copy out:**

```
\copy (SELECT id, email FROM users) TO 'users.csv' CSV HEADER
```

## ⚠️ Pitfalls [#️-pitfalls]

* Passwords on the command line leak via process lists — prefer `.pgpass` or env URL carefully.
* `\d` shows one schema search\_path view — check `\dn` / qualify schema names.
* Interactive transactions left open (`BEGIN` without `COMMIT`) block others.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/postgres/getting-started)
* [roles\_privileges.md](/docs/postgres/roles-privileges)
* [explain\_analyze.md](/docs/postgres/explain-analyze)
* [backups\_restore.md](/docs/postgres/backups-restore)


---

# Connection Pooling (/docs/postgres/connection-pooling)



# Connection Pooling [#connection-pooling]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Each Postgres connection is expensive (memory, process). Poolers like PgBouncer multiplex many client connections onto fewer server connections — essential for serverless and high-churn apps.

## 🔧 Core concepts [#-core-concepts]

| Mode (PgBouncer) | Behavior                                    |
| ---------------- | ------------------------------------------- |
| Session          | One server conn per client session          |
| Transaction      | Return conn after each transaction (common) |
| Statement        | Extreme multiplexing; breaks many features  |

| Concept             | Detail                           |
| ------------------- | -------------------------------- |
| `max_connections`   | Server hard limit                |
| Pool size           | App + pooler sizing              |
| Idle timeouts       | Reap abandoned clients           |
| Prepared statements | Need care in transaction pooling |

## 💡 Examples [#-examples]

**Check connections:**

```sql
SELECT count(*), state FROM pg_stat_activity GROUP BY state;
SHOW max_connections;
```

**Terminate idle (careful):**

```sql
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND state_change < now() - interval '10 minutes';
```

**App URL via pooler (sketch):**

```
postgres://user:pass@pgbouncer-host:6432/app
```

## ⚠️ Pitfalls [#️-pitfalls]

* Opening a new DB connection per serverless invoke without a pooler exhausts `max_connections`.
* Session-level features (temp tables, advisory locks, prepared statements) break under transaction pooling.
* Pooler + ORM defaults can still stampede — size pools per instance deliberately.

## 🔗 Related [#-related]

* [roles\_privileges.md](/docs/postgres/roles-privileges)
* [vacuum\_analyze.md](/docs/postgres/vacuum-analyze)
* [getting\_started.md](/docs/postgres/getting-started)
* [connect\_psql.md](/docs/postgres/connect-psql)


---

# EXPLAIN & ANALYZE (/docs/postgres/explain-analyze)



# EXPLAIN & ANALYZE [#explain--analyze]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`EXPLAIN` shows the planner’s chosen plan; `EXPLAIN ANALYZE` executes the query and adds actual timings/rows. Essential for diagnosing slow queries and verifying indexes.

## 🔧 Core concepts [#-core-concepts]

| Option     | Adds                            |
| ---------- | ------------------------------- |
| `ANALYZE`  | Actual runtime stats            |
| `BUFFERS`  | Shared/hit/read buffer counts   |
| `VERBOSE`  | Extra detail                    |
| `WAL`      | WAL generation (newer versions) |
| `SETTINGS` | Relevant GUCs                   |

| Node tip                   | Meaning            |
| -------------------------- | ------------------ |
| Seq Scan                   | Full table read    |
| Index Scan / Only          | Using index        |
| Nested Loop / Hash / Merge | Join strategies    |
| rows vs actual rows        | Estimator accuracy |

## 💡 Examples [#-examples]

**Basic:**

```sql
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42;
```

**With buffers:**

```sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT o.*
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE u.email = 'ada@example.com';
```

**Compare plans:**

```sql
SET enable_seqscan = off; -- diagnostic only
EXPLAIN ANALYZE SELECT ...;
```

## ⚠️ Pitfalls [#️-pitfalls]

* `EXPLAIN ANALYZE` runs the query — careful with writes (use a transaction + `ROLLBACK` when testing DML).
* Stale statistics → bad plans — `ANALYZE` the tables.
* Reading plans takes practice — start with the most expensive node (time).

## 🔗 Related [#-related]

* [indexes.md](/docs/postgres/indexes)
* [vacuum\_analyze.md](/docs/postgres/vacuum-analyze)
* [connect\_psql.md](/docs/postgres/connect-psql)
* [json\_jsonb.md](/docs/postgres/json-jsonb)


---

# Extensions (/docs/postgres/extensions)



# Extensions [#extensions]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Extensions add types, functions, and index methods packaged with Postgres or from contrib/third parties. Enable per database with `CREATE EXTENSION`.

## 🔧 Core concepts [#-core-concepts]

| Extension                    | Common use                     |
| ---------------------------- | ------------------------------ |
| `pgcrypto`                   | Crypto helpers                 |
| `uuid-ossp` / `pgcrypto` gen | UUID generation                |
| `pg_trgm`                    | Trigram fuzzy search / indexes |
| `citext`                     | Case-insensitive text          |
| `btree_gin` / `btree_gist`   | Combined index support         |
| `postgres_fdw`               | Foreign data wrapper           |
| `vector` (pgvector)          | Embeddings (external)          |

| Command                   | Role                       |
| ------------------------- | -------------------------- |
| `CREATE EXTENSION`        | Install in current DB      |
| `DROP EXTENSION`          | Remove                     |
| `\dx`                     | List installed             |
| `pg_available_extensions` | What’s available on server |

## 💡 Examples [#-examples]

**Enable trigram:**

```sql
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX users_name_trgm ON users USING GIN (name gin_trgm_ops);
```

**List:**

```
\dx
```

```sql
SELECT * FROM pg_available_extensions ORDER BY name;
```

**UUID:**

```sql
CREATE EXTENSION IF NOT EXISTS pgcrypto;
SELECT gen_random_uuid();
```

## ⚠️ Pitfalls [#️-pitfalls]

* Extension availability differs on managed hosts — check provider allowlists.
* Dump/restore may require extensions created before data load.
* Superuser is often required to create extensions.

## 🔗 Related [#-related]

* [indexes.md](/docs/postgres/indexes)
* [json\_jsonb.md](/docs/postgres/json-jsonb)
* [roles\_privileges.md](/docs/postgres/roles-privileges)
* [getting\_started.md](/docs/postgres/getting-started)


---

# Getting Started with Postgres Ops (/docs/postgres/getting-started)



# Getting Started with Postgres Ops [#getting-started-with-postgres-ops]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

PostgreSQL is a relational database used as a system of record. This folder focuses on operations and administration: connections, roles, indexes, vacuum, explain, backups, pooling, and JSONB — not basic SELECT tutorials.

## 🔧 Core concepts [#-core-concepts]

| Idea      | Meaning                                     |
| --------- | ------------------------------------------- |
| Cluster   | A Postgres data directory + running server  |
| Database  | Named DB inside a cluster                   |
| Role      | User/group identity for authz               |
| WAL       | Write-ahead log for durability/replication  |
| Extension | Packaged server plugin (`CREATE EXTENSION`) |

| Tool                     | Purpose                         |
| ------------------------ | ------------------------------- |
| `psql`                   | Interactive SQL + meta-commands |
| `pg_dump` / `pg_restore` | Logical backup/restore          |
| `pg_basebackup`          | Physical base backup            |
| Connection pooler        | PgBouncer / cloud poolers       |

## 💡 Examples [#-examples]

**Run Postgres (Docker):**

```shellscript
docker run --rm -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:16
```

**Connect:**

```shellscript
psql "postgres://postgres:postgres@127.0.0.1:5432/postgres"
```

**Version + basics:**

```sql
SELECT version();
SELECT current_database(), current_user;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Exposing `5432` publicly without TLS/auth hardening is dangerous.
* Superuser for app runtimes violates least privilege.
* Skipping backups until first incident is not a strategy.

## 🔗 Related [#-related]

* [connect\_psql.md](/docs/postgres/connect-psql)
* [roles\_privileges.md](/docs/postgres/roles-privileges)
* [backups\_restore.md](/docs/postgres/backups-restore)
* [glossary.md](/docs/postgres/glossary)


---

# Glossary (/docs/postgres/glossary)



# Glossary [#glossary]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Alphabetical glossary of PostgreSQL operations and administration terms.

## 🔧 Core concepts [#-core-concepts]

| Term             | Definition                                               |
| ---------------- | -------------------------------------------------------- |
| Autovacuum       | Background process that vacuums and analyzes tables.     |
| Bloat            | Excess space from dead tuples / index waste.             |
| Checkpoint       | Flush dirty buffers and advance WAL recovery point.      |
| Concurrent index | Index build that avoids long write locks.                |
| Extension        | Packaged set of DB objects installed per database.       |
| Hot standby      | Replica open for read-only queries.                      |
| MVCC             | Multi-version concurrency control for readers/writers.   |
| PITR             | Point-in-time recovery using base backup + WAL.          |
| Pooler           | Middleware multiplexing client connections.              |
| Role             | Auth identity that can own objects and hold privileges.  |
| TOAST            | Out-of-line storage for large field values.              |
| Vacuum           | Cleanup of dead row versions for reuse.                  |
| WAL              | Write-ahead log guaranteeing durability and replication. |
| Wraparound       | Transaction ID exhaustion risk mitigated by freezing.    |

## 💡 Examples [#-examples]

**Activity snapshot:**

```sql
SELECT pid, usename, state, query_start, left(query, 80)
FROM pg_stat_activity
WHERE state <> 'idle';
```

**Extension list:**

```
\dx
```

## ⚠️ Pitfalls [#️-pitfalls]

* Glossaries compress nuance — always confirm behavior for your major version (14/15/16/17).
* Managed Postgres may rename or restrict low-level ops (superuser, FS access).

## 🔗 Related [#-related]

* [getting\_started.md](/docs/postgres/getting-started)
* [vacuum\_analyze.md](/docs/postgres/vacuum-analyze)
* [backups\_restore.md](/docs/postgres/backups-restore)
* [README.md](/docs/postgres)


---

# Indexes (/docs/postgres/indexes)



# Indexes [#indexes]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Indexes speed lookups and enforce uniqueness at the cost of write overhead and storage. Choose type based on query patterns (equality, range, JSON, text search).

## 🔧 Core concepts [#-core-concepts]

| Type             | Good for                                |
| ---------------- | --------------------------------------- |
| B-tree (default) | `=`, `&lt;`, `>`, `BETWEEN`, `ORDER BY` |
| Hash             | Equality only (less common)             |
| GIN              | JSONB, arrays, full-text                |
| GiST             | Geometry, ranges, some text             |
| BRIN             | Very large append-only time series      |

| Command                     | Role                |
| --------------------------- | ------------------- |
| `CREATE INDEX`              | Add index           |
| `CREATE UNIQUE INDEX`       | Uniqueness          |
| `CREATE INDEX CONCURRENTLY` | Online create (ops) |
| `DROP INDEX`                | Remove              |
| `REINDEX`                   | Rebuild             |

## 💡 Examples [#-examples]

**B-tree + partial:**

```sql
CREATE INDEX CONCURRENTLY users_email_lower_idx
  ON users (lower(email));

CREATE INDEX CONCURRENTLY orders_open_idx
  ON orders (created_at)
  WHERE status = 'open';
```

**JSONB GIN:**

```sql
CREATE INDEX CONCURRENTLY events_payload_gin
  ON events USING GIN (payload jsonb_path_ops);
```

**Find unused-ish indexes (heuristic):**

```sql
SELECT * FROM pg_stat_user_indexes ORDER BY idx_scan NULLS FIRST LIMIT 20;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Over-indexing slows writes and bloats storage.
* Non-concurrent index builds lock writes — use `CONCURRENTLY` in prod (with caveats).
* Function indexes only help when queries use the same expression.

## 🔗 Related [#-related]

* [explain\_analyze.md](/docs/postgres/explain-analyze)
* [vacuum\_analyze.md](/docs/postgres/vacuum-analyze)
* [json\_jsonb.md](/docs/postgres/json-jsonb)
* [migrations\_ops.md](/docs/postgres/migrations-ops)


---

# JSON & JSONB (/docs/postgres/json-jsonb)



# JSON & JSONB [#json--jsonb]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`json` stores text as-is; `jsonb` stores a binary decomposed form — better for indexing and containment queries. Prefer `jsonb` for operational query patterns.

## 🔧 Core concepts [#-core-concepts]

| Type    | Trait                                      |
| ------- | ------------------------------------------ |
| `json`  | Preserves whitespace/key order; reparsed   |
| `jsonb` | Dedupes keys; indexable; usually preferred |

| Operator / fn | Role                           |            |
| ------------- | ------------------------------ | ---------- |
| `->` / `->>`  | Get object field (json / text) |            |
| `#>` / `#>>`  | Path extract                   |            |
| `@>`          | Contains                       |            |
| `?` / \`?     | `/`?&\`                        | Key exists |
| `jsonb_set`   | Modify                         |            |
| GIN index     | Accelerate `@>` / path ops     |            |

## 💡 Examples [#-examples]

**Query fields:**

```sql
SELECT payload->>'event'
FROM events
WHERE payload @> '{"type":"signup"}';
```

**GIN index:**

```sql
CREATE INDEX CONCURRENTLY events_payload_gin
  ON events USING GIN (payload jsonb_path_ops);
```

**Update key:**

```sql
UPDATE users
SET prefs = jsonb_set(prefs, '{theme}', '"dark"', true)
WHERE id = 42;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Unindexed `payload->>'x' =` on large tables seq-scans — express as jsonb ops + GIN when possible.
* Turning everything into JSONB abandons relational constraints — hybrid carefully.
* `json` vs `jsonb` equality and duplicate-key behavior differ.

## 🔗 Related [#-related]

* [indexes.md](/docs/postgres/indexes)
* [explain\_analyze.md](/docs/postgres/explain-analyze)
* [extensions.md](/docs/postgres/extensions)
* [migrations\_ops.md](/docs/postgres/migrations-ops)


---

# Migrations Ops (/docs/postgres/migrations-ops)



# Migrations Ops [#migrations-ops]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Schema changes in production need expand/contract discipline, lock awareness, and backwards-compatible deploys. Tooling (Flyway, Liquibase, Prisma, Alembic, golang-migrate) applies SQL — ops principles stay the same.

## 🔧 Core concepts [#-core-concepts]

| Practice                        | Why                          |
| ------------------------------- | ---------------------------- |
| Expand/contract                 | Avoid dual-write downtime    |
| Backwards compatible migrations | Old app + new schema coexist |
| Short transactions              | Reduce lock duration         |
| `CONCURRENTLY` indexes          | Avoid long write locks       |
| Migration history table         | Idempotent applies           |

| Risky DDL                   | Safer approach                     |
| --------------------------- | ---------------------------------- |
| Rewrite huge table in place | Add column → backfill → switch     |
| `ALTER TYPE` recreates      | Add new column/type carefully      |
| Long `ALTER TABLE` locks    | Check `pg_locks` / schedule window |

## 💡 Examples [#-examples]

**Add nullable column (safe):**

```sql
ALTER TABLE users ADD COLUMN locale text;
```

**Backfill in batches (app job):**

```sql
UPDATE users SET locale = 'en' WHERE locale IS NULL AND id IN (
  SELECT id FROM users WHERE locale IS NULL ORDER BY id LIMIT 1000
);
```

**Online index:**

```sql
CREATE INDEX CONCURRENTLY users_locale_idx ON users (locale);
```

## ⚠️ Pitfalls [#️-pitfalls]

* Running `CREATE INDEX` without `CONCURRENTLY` on large tables locks writes.
* Multi-statement migrations without transactions (or with ones that can't run in a txn, like concurrent index) need clear tool support.
* Ignoring failed mid-migration state leaves environments drifted.

## 🔗 Related [#-related]

* [indexes.md](/docs/postgres/indexes)
* [roles\_privileges.md](/docs/postgres/roles-privileges)
* [backups\_restore.md](/docs/postgres/backups-restore)
* [explain\_analyze.md](/docs/postgres/explain-analyze)


---

# Roles & Privileges (/docs/postgres/roles-privileges)



# Roles & Privileges [#roles--privileges]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Postgres uses roles for authentication and authorization. Prefer least privilege: separate owner, migrator, and runtime app roles.

## 🔧 Core concepts [#-core-concepts]

| Concept            | Meaning                     |
| ------------------ | --------------------------- |
| LOGIN role         | Can connect (user)          |
| NOLOGIN role       | Group / ownership bucket    |
| GRANT / REVOKE     | Privilege changes           |
| `SEARCH_PATH`      | Schema resolution order     |
| Row Level Security | Per-row policies (advanced) |

| Privilege                      | Typical on tables     |
| ------------------------------ | --------------------- |
| `SELECT`                       | Read                  |
| `INSERT` / `UPDATE` / `DELETE` | Write                 |
| `TRUNCATE`                     | Fast empty            |
| `REFERENCES`                   | FK creation           |
| `USAGE` on schema              | See objects in schema |

## 💡 Examples [#-examples]

**Create app role:**

```sql
CREATE ROLE app_login LOGIN PASSWORD 'change-me';
CREATE ROLE app_owner NOLOGIN;
GRANT app_owner TO migrator; -- migrator assumes ownership duties
```

**Grants:**

```sql
GRANT USAGE ON SCHEMA public TO app_login;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_login;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_login;
```

**Inspect:**

```
\du
```

```sql
SELECT * FROM information_schema.role_table_grants WHERE grantee = 'app_login';
```

## ⚠️ Pitfalls [#️-pitfalls]

* Objects created by superuser may not grant to app roles unless `ALTER DEFAULT PRIVILEGES` is set.
* Public schema open grants are a common over-exposure.
* Rotating passwords in URLs requires updating all poolers/clients.

## 🔗 Related [#-related]

* [connect\_psql.md](/docs/postgres/connect-psql)
* [migrations\_ops.md](/docs/postgres/migrations-ops)
* [connection\_pooling.md](/docs/postgres/connection-pooling)
* [getting\_started.md](/docs/postgres/getting-started)


---

# VACUUM & ANALYZE (/docs/postgres/vacuum-analyze)



# VACUUM & ANALYZE [#vacuum--analyze]

*Postgres · Reference cheat sheet*

***

## 📋 Overview [#-overview]

MVCC leaves dead row versions. `VACUUM` reclaims space for reuse; `ANALYZE` updates planner statistics. Autovacuum handles most cases — watch bloat and freeze age.

## 🔧 Core concepts [#-core-concepts]

| Command                     | Role                           |
| --------------------------- | ------------------------------ |
| `VACUUM`                    | Cleanup dead tuples            |
| `VACUUM (VERBOSE, ANALYZE)` | Cleanup + stats                |
| `VACUUM FULL`               | Rewrite table (exclusive lock) |
| `ANALYZE`                   | Refresh stats only             |
| Autovacuum                  | Background workers             |

| Monitor             | View                             |
| ------------------- | -------------------------------- |
| Dead tuples         | `pg_stat_user_tables`            |
| Autovacuum activity | logs / `pg_stat_progress_vacuum` |
| Wraparound risk     | `age(datfrozenxid)`              |

## 💡 Examples [#-examples]

**Targeted maintenance:**

```sql
VACUUM (ANALYZE) orders;
```

**Check bloat signals:**

```sql
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;
```

**Aggressive rewrite (maintenance window):**

```sql
VACUUM FULL orders; -- locks heavily; prefer wisely
```

## ⚠️ Pitfalls [#️-pitfalls]

* `VACUUM FULL` is not routine — it locks and needs disk headroom.
* Disabling autovacuum “for performance” causes wraparound emergencies.
* Long transactions delay vacuum — find idle-in-transaction sessions.

## 🔗 Related [#-related]

* [explain\_analyze.md](/docs/postgres/explain-analyze)
* [indexes.md](/docs/postgres/indexes)
* [connection\_pooling.md](/docs/postgres/connection-pooling)
* [getting\_started.md](/docs/postgres/getting-started)

