{"post":{"slug":"cascade-deletes-explained-2026","title":"Cascade Deletes: Convenient Until They Are Not","excerpt":"Deleting a parent and having children disappear automatically is tidy. It also means one statement can delete far more than you intended, slowly, holding locks.","category":"code","date":"February 12, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">D</span>elete a customer and their orders, their order lines, their addresses, and their payment methods all disappear automatically. No application code to write, no orphans left behind, nothing forgotten.\n\nThat is genuinely useful. It also means a single `DELETE` statement against one row can remove millions of rows across a dozen tables, take minutes, and hold locks the whole time — and nothing in the statement suggests it will.\n\n## What changed in 2026\n\n- **Retention requirements complicated cascades.** Rules about what must be kept made blanket deletion less appropriate for some child data.\n- **Soft delete interactions became clearer.** Cascades do not follow soft-delete flags, which produces inconsistency — see [soft delete patterns](/blog/soft-delete-patterns-2026).\n- **The missing-index problem stayed common.** Unindexed child foreign keys remained a frequent cause of slow deletes.\n- **Restrict-by-default gained ground.** More teams chose explicit deletion over automatic cascading.\n\n## The referential actions\n\n| Action | On parent delete | Suits |\n| --- | --- | --- |\n| `NO ACTION` / `RESTRICT` | Error if children exist | Default; forces explicitness |\n| `CASCADE` | Delete children too | Genuinely dependent data |\n| `SET NULL` | Keep children, clear the link | Optional relationships |\n| `SET DEFAULT` | Keep children, set a default | Rare |\n\nThe question that decides which: **does the child have meaning without the parent?**\n\nAn order line has no meaning without its order — cascade is right. An order has considerable meaning without the customer record, particularly for accounting and legal retention — cascade is wrong, and `SET NULL` or restrict is better.\n\nA comment on a deleted post is arguable and depends on the product.\n\nGetting this wrong in the cascade direction is worse than getting it wrong in the restrict direction. Restrict produces an error you notice; cascade produces silent data loss you discover later.\n\n## The index requirement\n\nThe performance trap. When a parent row is deleted, the database must find the children referencing it. That lookup uses an index on the child's foreign key column — and **databases do not create that index automatically** in most engines.\n\nWithout it, every parent deletion scans the entire child table. Deleting one customer scans the orders table. Deleting a hundred scans it a hundred times.\n\nThis is one of the most common causes of a delete that is inexplicably slow, and the fix is a single index on the referencing column. It is worth auditing: list foreign keys without a supporting index on the child side, and add them.\n\nThe cascade also acquires locks on every affected row across every affected table, which on a deep cascade means a long-running transaction holding many locks — with the knock-on effects described in [MVCC explained](/blog/mvcc-explained-2026).\n\n## Depth and blast radius\n\nCascades chain. Customer cascades to orders, orders cascade to lines, lines cascade to allocations. A single statement traverses the whole graph.\n\nNothing in the statement indicates this. `DELETE FROM customers WHERE id = 5` looks like it deletes one row.\n\nTwo disciplines help. **Know the depth** — map which relationships cascade before relying on them, ideally as part of schema review. And **delete explicitly for large operations** — issuing the child deletes yourself, in batches, gives you control over transaction size and progress visibility that a single cascading statement does not.\n\nFor bulk cleanup, explicit batched deletion is almost always better than a cascade, because you can bound each transaction and observe progress.\n\n## Common mistakes\n\n- **Cascade where the child has independent value.** Silent loss of data you needed.\n- **No index on the child foreign key.** Every cascade scans.\n- **Bulk deletes relying on cascade.** One enormous transaction.\n- **Not knowing the cascade depth.** Blast radius larger than expected.\n- **Mixing cascade with soft delete.** Cascades ignore the flag, producing inconsistency.\n- **Cascade on audit or history tables.** Defeats their purpose entirely.\n- **Assuming restrict is the default everywhere.** Check; engines differ.\n\n## FAQ\n\n**Should I use cascade at all?**\nFor genuinely dependent data with bounded child counts, it is clean and safe. For anything with independent value, or unbounded child counts, prefer explicit deletion.\n\n**How do I find missing foreign key indexes?**\nQuery the catalog for foreign key constraints and check whether a matching index exists on the referencing side. Worth running as a periodic audit — most schemas have a few.\n\n**What about cascading updates?**\nSame mechanism for changed keys, and generally a sign the key should be immutable. Changing a primary key is rarely something to design for.\n\n**Does cascade work with soft delete?**\nNo, and this is a real inconsistency. Soft-deleting a parent leaves children untouched, since no actual delete occurred — you must handle it in application logic, per [soft delete patterns](/blog/soft-delete-patterns-2026).\n\n## Where to go next\n\nFor the soft-delete interaction, read [soft delete patterns](/blog/soft-delete-patterns-2026). For the indexes cascades require, [database indexing explained](/blog/database-indexing-explained-2026), and for the long-transaction effects of large deletes, [MVCC explained](/blog/mvcc-explained-2026).","hue":319,"metaTitle":"Cascade Deletes: Convenient Until They Are Not","metaDescription":"How foreign key cascade deletes multiply across levels, why child foreign keys need indexes, and when restrict or set null is the better rule.","keywords":["cascade delete","foreign key on delete","referential actions","restrict vs cascade","orphaned rows","delete performance","relational integrity","database design 2026"],"tldr":["**A cascade can traverse several levels** — deleting one row may remove millions.","**Cascading deletes need an index on the child foreign key** — without one each cascade scans.","**Restrict is the safer default** — force the caller to be explicit about what they are removing.","**Set null is frequently the right choice for optional relationships** — keep the child, clear the link.","**Skip:** cascade on relationships where the child has independent value. Orders should outlive a deleted customer record."],"readTime":"4 min read","wordCount":823},"related":[{"slug":"what-is-a-database-schema-2026","title":"What Is a Database Schema in 2026: the blueprint for data","excerpt":"A database schema is the blueprint that defines how data is organized: the tables, columns, types, and relationships. Here is what a schema is and why it matters.","category":"code","date":"June 22, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":222},{"slug":"database-design-patterns-2026","title":"Database design patterns in 2026: practical patterns that scale","excerpt":"The database patterns that survive contact with real traffic are boring and well-known. Here is the 2026 practical guide — indexes, denormalization, soft deletes, audit trails, and the trade-offs.","category":"code","date":"February 13, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":152},{"slug":"ci-cd-caching-strategies-2026","title":"CI/CD Caching Strategies That Actually Cut Build Time","excerpt":"Most CI caches are configured wrong and quietly miss on every run. Here is how to design cache keys, what to cache, and how to tell whether it is working.","category":"code","date":"August 17, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":150}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"breach-response-checklist-2026","title":"Breach Response: What to Do When a Service You Use Is Hacked","excerpt":"A notification arrives saying your data was exposed. What matters is what was taken and where else you used the same password, and the first hour is worth more than the next week.","category":"guides","date":"February 12, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":146},"older":{"slug":"ci-cd-best-practices-2026","title":"CI/CD best practices in 2026: faster pipelines, secure deploys, sane gates","excerpt":"CI/CD pipelines accumulate technical debt fast. Here is the 2026 playbook for keeping them fast, secure, and gating the right things — without becoming the bottleneck.","category":"code","date":"February 12, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":155}}