PostgreSQL Knowledge Base
Source: Adapted from planetscale/database-skills (PostgreSQL skill).
Schema Design
- Prefer
BIGSERIALorBIGINT GENERATED ALWAYS AS IDENTITYfor PKs. - Use
TIMESTAMPTZ(with timezone) overTIMESTAMP. TEXTandVARCHARhave similar performance in PostgreSQL — preferTEXTunless length constraint is meaningful.- Use
NUMERICfor money, neverFLOAT/REAL. JSONB(binary) overJSON(text) for structured data.
Indexing
| Type | Use for |
|---|---|
| B-Tree (default) | Equality, range, sorting |
| GIN | JSONB, fulltext, arrays, containment |
| GiST | Geometry, range types, nearest-neighbor |
| BRIN | Sequential data (timestamps, IDs) on large tables |
| Hash | Equality only (rarely needed) |
- Partial indexes:
CREATE INDEX ... WHERE condition— index only relevant rows. - Expression indexes:
CREATE INDEX ... ON t (lower(name)). - Covering indexes:
INCLUDE (col1, col2)for index-only scans. CONCURRENTLYfor creating indexes without blocking writes.
JSONB
- Store structured, semi-structured, or variable-schema data.
- Index with GIN:
CREATE INDEX ... USING GIN (data jsonb_path_ops). - Query:
data->>'key'(text),data->'key'(jsonb),data @> '{"key": "val"}'(containment). - Generated columns for frequently queried JSONB paths.
Partitioning
- Declarative partitioning (range, list, hash) for large tables.
- Partition key must be part of every unique/PK constraint.
ATTACH PARTITION/DETACH PARTITIONfor maintenance.- Partition pruning: queries automatically skip irrelevant partitions.
Extensions
pg_trgm: trigram similarity for fuzzy search.pgvector: vector similarity search (AI/embeddings).pg_stat_statements: query performance analysis.uuid-ossp: UUID generation.postgis: geospatial data.
Connection Management
- Use connection pooling (PgBouncer) — PostgreSQL connections are expensive (~5-10 MB each).
- Pool sizing: start with
2 * CPU cores + 1. - Use
prepared_statementsfor parameterized queries. - Set
statement_timeoutto prevent runaway queries.
Guardrails
- Always use
TIMESTAMPTZ, notTIMESTAMP. - Prefer
TEXToverVARCHAR(N)unless length limit is meaningful. - Use
CONCURRENTLYwhen creating indexes on production tables. - Set
statement_timeoutat connection or session level. - Use PgBouncer for connection pooling in production.