| name | postgres-patterns |
| description | PostgreSQL schema, query, indexing, and performance patterns. |
| origin | FlowDeck |
postgres-patterns
When to Activate
When designing database schemas, writing complex queries, or optimizing database performance. Use before creating migrations or writing SQL queries.
Steps
- Design indexes strategically - Create individual btree indexes on each column for multi-column searches (allows BitmapAnd)
- Use EXPLAIN ANALYZE - Always verify query plans before and after optimization
- Choose correct index type - B-tree for equality/range, Bloom for multi-column filters with high selectivity
- Avoid multi-column btree on non-leading columns - Queries on non-first columns of multi-column btree indexes will do sequential scans
- Use parameterized queries - Let the planner cache and reuse query plans
- Run ANALYZE regularly - Keep statistics fresh for optimal planner decisions
Examples
CREATE INDEX btreeidx ON tbloom (i1, i2, i3, i4, i5, i6);
CREATE INDEX btreeidx1 ON tbloom (i1);
CREATE INDEX btreeidx2 ON tbloom (i2);
CREATE INDEX btreeidx3 ON tbloom (i3);
CREATE INDEX btreeidx4 ON tbloom (i4);
CREATE INDEX btreeidx5 ON tbloom (i5);
CREATE INDEX btreeidx6 ON tbloom (i6);
CREATE INDEX bloomidx ON tbloom USING bloom (i1, i2, i3, i4, i5, i6);
EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;
SET enable_hashjoin = off;
SET enable_seqscan = off;
SET random_page_cost = 1.1;
SET effective_cache_size = '8GB';
ANALYZE;
ALTER TABLE orders SET STATISTICS = 500;
ANALYZE orders;
interface OrderRepository {
findAll(filter: OrderFilter, pagination: Pagination): Promise<Order[]>;
findById(id: string): Promise<Order | null>;
create(order: CreateOrderDTO): Promise<Order>;
update(id: string, attributes: UpdateOrderDTO): Promise<Order>;
delete(id: string): Promise<void>;
count(filter?: OrderFilter): Promise<number>;
}
Related Skills
- api-design
- backend-patterns
- database-migrations
- postgres-performance