postgresql-table-design
PostgreSQL schema design covering best practices, data types, indexing, constraints, and performance patterns.
- Prioritize normalization to 3NF; denormalize only when join performance is proven problematic and measured for ROI.
- Use
BIGINT GENERATED ALWAYS AS IDENTITYfor primary keys unless global uniqueness or opacity requiresUUID; always add indexes on foreign key columns. - Choose data types carefully:
TIMESTAMPTZfor events,NUMERICfor money,TEXTfor strings,JSONBfor semi-structured data; avoidTIMESTAMP,VARCHAR(n),SERIAL, andMONEYtype. - Index strategically for actual query patterns: B-tree for equality/range, GIN for JSONB/arrays/full-text, GiST for ranges/geometry, BRIN for large time-series data.
- Partition tables >100M rows by range (time) or hash; use TimescaleDB for time-series automation; separate hot/cold columns and minimize indexes for insert-heavy workloads.
PostgreSQL Table Design
Core Rules
- Define a PRIMARY KEY for reference tables (users, orders, etc.). Not always needed for time-series/event/log data. When used, prefer
BIGINT GENERATED ALWAYS AS IDENTITY; useUUIDonly when global uniqueness/opacity is needed. - Normalize first (to 3NF) to eliminate data redundancy and update anomalies; denormalize only for measured, high-ROI reads where join performance is proven problematic. Premature denormalization creates maintenance burden.
- Add NOT NULL everywhere it’s semantically required; use DEFAULTs for common values.
- Create indexes for access paths you actually query: PK/unique (auto), FK columns (manual!), frequent filters/sorts, and join keys.
- Prefer TIMESTAMPTZ for event time; NUMERIC for money; TEXT for strings; BIGINT for integer values, DOUBLE PRECISION for floats (or
NUMERICfor exact decimal arithmetic).
PostgreSQL “Gotchas”
- Identifiers: unquoted → lowercased. Avoid quoted/mixed-case names. Convention: use
snake_casefor table/column names. - Unique + NULLs: UNIQUE allows multiple NULLs. Use
UNIQUE (...) NULLS NOT DISTINCT(PG15+) to restrict to one NULL. - FK indexes: PostgreSQL does not auto-index FK columns. Add them.
- No silent coercions: length/precision overflows error out (no truncation). Example: inserting 999 into
NUMERIC(2,0)fails with error, unlike some databases that silently truncate or round. - Sequences/identity have gaps (normal; don't "fix"). Rollbacks, crashes, and concurrent transactions create gaps in ID sequences (1, 2, 5, 6...). This is expected behavior—don't try to make IDs consecutive.
- Heap storage: no clustered PK by default (unlike SQL Server/MySQL InnoDB);
CLUSTERis one-off reorganization, not maintained on subsequent inserts. Row order on disk is insertion order unless explicitly clustered. - MVCC: updates/deletes leave dead tuples; vacuum handles them—design to avoid hot wide-row churn.
More from wshobson/agents
tailwind-design-system
Build scalable design systems with Tailwind CSS v4, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.
41.0Ktypescript-advanced-types
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects.
40.4Knodejs-backend-patterns
Build production-ready Node.js backend services with Express/Fastify, implementing middleware patterns, error handling, authentication, database integration, and API design best practices. Use when creating Node.js servers, REST APIs, GraphQL backends, or microservices architectures.
31.8Kpython-performance-optimization
Profile and optimize Python code using cProfile, memory profilers, and performance best practices. Use when debugging slow Python code, optimizing bottlenecks, or improving application performance.
22.1Kapi-design-principles
Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
20.3Kpython-testing-patterns
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development. Use when writing Python tests, setting up test suites, or implementing testing best practices.
19.7K