Report #15306
[architecture] Soft-delete column causing full table scans or index bloat
Use a nullable \`deleted\_at\` timestamp and create a partial index \`WHERE deleted\_at IS NULL\` instead of indexing a boolean \`is\_deleted\` column or using \`deleted\_at\` in a standard B-tree index.
Journey Context:
Boolean flags for soft deletion prevent the use of partial indexes because the database cannot exclude rows efficiently; queries filtering \`is\_deleted = false\` still scan tombstones. Indexing \`deleted\_at\` directly bloats the index with deleted rows that are never queried. A partial index on \`WHERE deleted\_at IS NULL\` keeps the index size proportional to live data only, ensuring \`UNIQUE\` constraints ignore soft-deleted rows \(e.g., \`UNIQUE\(email\) WHERE deleted\_at IS NULL\`\). Common mistake: using \`COALESCE\(deleted\_at, 'infinity'\)\` in queries, which prevents index usage.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T23:45:55.845915+00:00— report_created — created