bloat |
bloat |
Bloat is dead row versions and empty pages still stored in a table or index after updates and deletes. It makes tables larger on disk and forces queries to scan pages that hold no live data. Regular vacuuming reclaims this space for reuse. |
Run VACUUM (VERBOSE, ANALYZE) on the named table during a quiet window, then re-run pgdba to confirm the finding clears. |
vacuum |
VACUUM |
VACUUM is the cleanup command that marks dead row versions as reusable space. It does not lock the table against reads or writes. Running it regularly keeps tables lean and statistics fresh. |
Run VACUUM ANALYZE on the named table any time; it stays safe for normal queries. |
sighup |
sighup |
Sighup is a configuration reload that applies certain settings without restarting the database. Connections stay up and queries keep running. Only settings marked as reloadable take effect this way. |
After changing a sighup-level setting, apply it with SELECT pg_reload_conf() and verify with SHOW. |
restart-required |
restart-required |
Restart-required means a setting only takes effect after the whole database server restarts. Until then the old value keeps running. A restart briefly disconnects every session. |
Schedule a maintenance window for the change and confirm the new value with SHOW after the restart. |
rewrite lock |
rewrite lock |
A rewrite lock is taken when ALTER TABLE rewrites every row, blocking writes until the rewrite finishes. Reads may also stall on large tables. It is the highest-risk routine operation. |
Never run a rewriting ALTER unprompted; use a concurrent migration pattern or a planned maintenance window instead. |
checkpoint |
checkpoint |
A checkpoint is when the database flushes dirty pages from memory to disk. Frequent checkpoints add write spikes that slow bursts of inserts. Tuning spreads them out over time. |
Review checkpoint-related findings with your DBA before changing any setting; observe one full workload cycle first. |
wal |
WAL |
WAL, the write-ahead log, is the journal where every change is recorded before it reaches table files. It powers crash recovery and replication. Unbounded WAL growth fills disks. |
Check for stale replication slots before touching WAL settings; dropping a dead slot is the usual safe fix. |
pg_stat_statements |
pg_stat_statements |
pg_stat_statements is an extension that records how often each query runs and how long it takes. It is the main source for finding slow queries. Enabling it the first time needs a restart. |
Add it to shared_preload_libraries in a maintenance window, restart once, then re-run pgdba for query advice. |
hypopg |
HypoPG |
HypoPG is an extension that simulates hypothetical indexes without building them. It answers whether an index would help in seconds with no locks. Its advice is an estimate, not a guarantee. |
Install HypoPG to preview index advice, then create winners with CREATE INDEX CONCURRENTLY. |
hnsw |
HNSW |
HNSW is an index type for fast nearest-neighbor search over vector embeddings. It trades recall for speed through graph navigation. Wrong settings silently return fewer good matches. |
Create HNSW indexes with CONCURRENTLY and validate recall on sample queries before relying on them. |
vector |
vector |
A vector is a list of numbers representing meaning, used for similarity search. The pgvector extension adds the vector type to Postgres. Without vector workloads, vector findings can be ignored. |
Ignore vector findings if you store no embeddings; otherwise install pgvector and re-run pgdba. |
idx_scan |
idx_scan |
idx_scan counts how many times an index has been used for scans. A zero count over a full workload cycle means the index only costs writes. pgdba flags such indexes as droppable. |
Confirm zero scans across a full cycle, then DROP INDEX CONCURRENTLY to stop paying write costs. |
write amplification |
write amplification |
Write amplification is extra disk writing caused by one logical change. Bloated tables and redundant indexes multiply every write. Fewer, leaner indexes reduce it. |
Drop unused indexes with DROP INDEX CONCURRENTLY to cut amplified writes. |
bpchar |
bpchar |
bpchar is the internal name for the CHAR(n) fixed-length type. It pads short values with spaces, wasting bytes on most workloads. TEXT with a check constraint usually fits better. |
Prefer TEXT for new columns; converting old ones takes a rewrite lock, so plan a window. |
seq_scan |
seq_scan |
A seq_scan reads every row of a table instead of using an index. It is fine for tiny tables but punishing for large ones. Rising seq_scan counts point at missing indexes. |
Add the suggested index with CREATE INDEX CONCURRENTLY, which never blocks writes. |
analyze |
ANALYZE |
ANALYZE samples a table to refresh the planner statistics. Fresh statistics stop the planner from picking slow plans. It never blocks reads or writes. |
Run ANALYZE on the named table any time; it is always safe. |
concurrently |
CONCURRENTLY |
CONCURRENTLY builds or drops an index without blocking writes. It takes longer than the blocking form and cannot run inside a transaction. It is the only safe way to change indexes on a live table. |
Always add CONCURRENTLY to CREATE INDEX and DROP INDEX on live tables. |
autovacuum |
autovacuum |
Autovacuum is the background worker that vacuums and analyzes tables automatically. It prevents bloat and wraparound outages. Falling behind shows as growing dead-tuple counts. |
Tune per-table thresholds rather than disabling it; never turn autovacuum off globally. |
toast |
TOAST |
TOAST is the overflow storage for values too large for a normal row. Large text and jsonb columns live there transparently. Churning wide values rewrites TOAST pages each time. |
Avoid rewriting wide columns in hot updates; move them to a side table if the finding persists. |
fillfactor |
fillfactor |
Fillfactor sets how full each table page is packed at write time. Leaving free space lets updates stay on the same page and avoids bloat. The default of 100 suits read-mostly tables. |
Lower fillfactor only on heavily updated tables, with a DBA review, since it also grows the table. |
acid |
ACID |
ACID is the four guarantees a transaction makes: atomicity (all or nothing), consistency (rules hold), isolation (concurrent transactions do not see each other’s half-work), and durability (committed data survives a crash). Weakening isolation trades the third guarantee for speed. |
Keep transactions short, take locks in a consistent order, and retry deadlocks. |
mvcc |
MVCC |
MVCC (multi-version concurrency control) is how PostgreSQL gives every reader a consistent snapshot without blocking writers: old row versions are kept until no snapshot needs them. A long-open transaction pins old versions everywhere it touched. |
Commit or roll back idle transactions promptly and split long-running ones into batches. |
wal lag |
WAL lag |
WAL lag is how far a standby trails the primary in write-ahead data, in bytes or seconds. The three lag clocks (write, flush, replay) each point at a different bottleneck: network, standby disk, or standby CPU/conflicts. |
Fix the dominant clock first; sustained minutes or gigabytes mean failover would lose data. |
slots |
slots |
A replication slot asks the primary to keep every write-ahead record a consumer has not confirmed yet. A slot nobody reads pins those records forever, and the directory holding them grows until the disk fills. |
Drop dead slots with pg_drop_replication_slot, or revive the consumer that owns them. |
pitr |
PITR |
Point-in-time recovery (PITR) rebuilds a database to any chosen moment by replaying archived write-ahead records on top of a base backup. The chain has two links: the base backup and the archive stream; either failing breaks the recovery point. |
Keep the archiver healthy and rehearse restores on a schedule. |
rto |
RTO |
Recovery time objective (RTO) is how long you can afford the database to be down after a failure. A restore rehearsal measures real throughput against it, replacing hope with a number. |
Measure restore throughput with pgdba verify-restore and size the RTO to the measured number, not the wish. |
colocation |
colocation |
Colocation places rows that share a key (usually the tenant) on the same shard, so joins between them stay on one node. Distributing by anything else scatters the join across the cluster. |
Distribute tenant tables by the tenant column and give related tables the same colocation group. |
normalization |
normalization |
Normalization is structuring data so each fact is stored once: repeated groups become child tables, and references become foreign keys. Denormalizing some of it for speed is fine — as long as it is a decision, not an accident. |
Normalize the live data, snapshot history into its own tables, and keep first-class filter columns as real columns. |
collation |
collation |
A collation is the ordering and comparison rules for text, provided by the operating system. When it changes version (say, after an OS upgrade), text indexes built under the old rules can be quietly wrong. |
Rebuild text indexes concurrently after an OS upgrade, then run ALTER COLLATION … REFRESH VERSION. |
sargable |
sargable |
A sargable predicate is one the planner can answer with an index: a bare column compared to a value. Wrapping the column in a function, or comparing across mismatched types, disables the index and forces a scan. |
Compare the raw column, fix the literal type, or add an expression index matching the wrapper. |
n-plus-1 |
N+1 |
An N+1 storm is one query fetching parents plus one query per parent fetching children: thousands of round trips and plans for work a single JOIN could do. It shows up as one fingerprint with extreme calls, tiny mean time, and ~1 row per call. |
Collapse the loop into one JOIN (or IN-list) fetching parents with children together. |
plan-flapping |
plan flapping |
Plan flapping is when the same query shape gets very different plans across executions — visible as runtime varying wildly relative to the mean. Parameter skew and stale statistics are the usual causes. |
Capture plans across parameter values, refresh statistics, and stabilize with better stats or plan pinning. |
rls |
RLS |
Row-level security filters which rows a role can see inside a table, using policies you define. Without it, any role with table privileges reads every tenant’s rows. Tables shared by multiple roles usually need it. |
Enable it with ALTER TABLE … ENABLE ROW LEVEL SECURITY, then add a policy matching your tenant column. |
security-definer |
SECURITY DEFINER |
A function marked SECURITY DEFINER runs with its owner’s privileges instead of the caller’s. If its search_path is not pinned, an attacker can plant a same-named object that the function then runs with elevated rights. |
Pin the path with ALTER FUNCTION … SET search_path = <schema>, pg_temp. |
search-path |
search_path |
search_path is the ordered list of schemas PostgreSQL searches for unqualified object names. Functions inherit the caller’s search_path unless pinned, which is why SECURITY DEFINER functions must set their own. |
Set an explicit search_path on definer functions, ending with pg_temp. |