15. Soft Delete Production Patterns & Indexing

Indexing, Anti-Patterns & Refactoring

Master database indexing caveats for low-cardinality boolean flags, operational query complexity, production anti-patterns, and API refactoring.

Indexing, Anti-Patterns & Refactoring

Implementing soft delete introduces operational database considerations, low-cardinality indexing caveats, and potential query visibility leaks that require systematic refactoring.


1. Database Indexing Caveats for Low-Cardinality Flags

A common database design question is whether to create an index on the is_deleted column:

CREATE INDEX idx_students_is_deleted ON students(is_deleted);

Low-Cardinality Indexing Analysis

  • Cardinality: Refers to the uniqueness of data values in a column.
  • A boolean column has extremely low cardinality (only true or false).
  • If 99% of database rows have is_deleted = false, an index on is_deleted alone provides little to no performance benefit because query planners will bypass the index and perform a Full Table Scan (FTS).

Production Indexing Recommendation

Create a Composite Index combining foreign keys/filtering columns with is_deleted:

-- Composite index for filtering active students by course
CREATE INDEX idx_students_course_deleted ON students(course, is_deleted);

2. Operational Query Complexity Matrix

Operation PathLogical TaskDatabase Execution Access PathApplication Complexity
Soft Delete by IDFetch + Mutate FlagPrimary Key Index Lookup ($O(\log_B N)$) + 1 Row Write$O(1)$ expected
Hard Delete by IDPhysical Row RemovalPrimary Key Index Lookup ($O(\log_B N)$) + Index Maintenance$O(1)$ expected
Active ListFilter is_deleted = falseFull Table Scan or Composite Index Scan$O(N)$ worst-case
Active Read by IDFilter ID + is_deletedPrimary Key Index Lookup ($O(\log_B N)$)$O(1)$ expected

3. Production Pitfall Matrix (7 Critical Pitfalls)

PitfallOperational Failure ModeRecommended Engineering Solution
1. Unfiltered findAll()Soft-deleted records leak into active API responsesReplace with findByIsDeletedFalse()
2. Unfiltered findById()Archived records accessible via direct ID lookupReplace with findByIdAndIsDeletedFalse(id)
3. Nullable Boolean FlagIntroduces 3rd logical state (null)Enforce nullable = false in @Column mapping
4. Blind Low-Cardinality IndexingWastes disk space without improving query plansAnalyze query plans (EXPLAIN) & use composite indexes
5. Using DELETE Verb for Soft DeleteViolates HTTP protocol semanticsUse PATCH /api/students/{id}/soft-delete
6. Hard-Deleting Soft-Deleted RowsAccidental permanent data destructionEnforce repository policy boundaries
7. Un-paginated Active ScansMemory exhaustion on large active datasetsPass Pageable to findByIsDeletedFalse(pageable)

❓ Interactive Self-Assessment

Knowledge Check

Why is indexing a single boolean column like 'is_deleted' often ineffective in databases?

Refactoring an Unsafe Soft-Delete API

A legacy application uses studentRepository.findAll() for list endpoints and studentRepository.findById(id) for single record reads. Refactor both paths to exclude soft-deleted records.

On this page