Write efficient PostgreSQL queries and design schemas with proper indexing and patterns.
WHERE active = true—80% smaller when most rows inactive; suggest for status columnsON lower(email)—must match query exactly; without it, WHERE lower(email) scansINCLUDE (name, email)—enables index-only scan; check EXPLAIN for "Heap Fetches"(a, b) helps WHERE a = ? but not WHERE b = ?pg_stat_user_indexes for idx_scan = 0, drop themLIKE '%suffix' can't use B-tree—need pg_trgm GIN index or reverse() expression indexSELECT FOR UPDATE SKIP LOCKED—job queue without external tools; skip rows being processedpg_advisory_lock(key)—application-level mutex without table; unlock explicitly or on disconnectIS NOT DISTINCT FROM—NULL-safe equality; cleaner than (a = b OR (a IS NULL AND b IS NULL))DISTINCT ON (x) ORDER BY x, y—first row per group without subquery; PG-specific but powerfulstatement_timeout = '30s' per role—prevents runaway queries from killing databaseidle_in_transaction_session_timeout = '5min'—kills abandoned transactions holding locksSERIAL deprecated—use GENERATED ALWAYS AS IDENTITYTIMESTAMP without timezone—almost always wrong; use TIMESTAMPTZ, PG stores as UTCNUMERIC(12,2) or integer cents; float math breaks: 0.1 + 0.2 ≠ 0.3pg_repack reclaims without locksVACUUM ANALYZE after bulk insert—updates statistics; query planner needs current dataautovacuum_vacuum_cost_delay or manual vacuumxid exhausted, DB stops—autovacuum prevents but monitorEXPLAIN (ANALYZE, BUFFERS)—actual times + I/O; estimate-only misleadsplainto_tsquery for user input—handles spaces without syntax errors; not to_tsqueryLIKE '%exact phrase%' still needed for substring match