推荐使用 deleted_at 时间戳字段实现软删除,NULL 表示未删除,非空表示已删除,支持审计、归档与索引优化,并需在 ORM 层统一过滤。

软删除字段通常用一个布尔型或时间戳字段来标记数据是否被“删除”,而不是真正从数据库中移除。设计时核心目标是:不影响原有查询逻辑、便于恢复、避免误删、兼顾性能和可读性。
推荐用 deleted_at 时间戳字段
比布尔字段(如 is_deleted)更灵活,能记录删除时间,支持按时间范围审计、自动归档或定时清理。值为 NULL 表示未删除,非空表示已软删除。
- 建表时添加:
deleted_at DATETIME NULL DEFAULT NULL - 查询未删除数据时统一加条件:
WHERE deleted_at IS NULL - 删除操作改为更新:
UPDATE users SET deleted_at = NOW() WHERE id = 123 - 恢复操作只需置空:
UPDATE users SET deleted_at = NULL WHERE id = 123
配合索引提升查询效率
大量数据下,WHERE deleted_at IS NULL 可能走全表扫描。建议为该字段建立单独索引,或与高频查询字段组合成联合索引。
NetShop软件特点介绍: 1、使用ASP.Net(c#)2.0、多层结构开发 2、前台设计不采用任何.NET内置控件读取数据,完全标签化模板处理,加快读取速度3、安全的数据添加删除读取操作,利用存储过程模式彻底防制SQL注入式攻击4、前台架构DIV+CSS兼容IE6,IE7,FF等,有利于搜索引挚收录5、后台内置强大的功能,整合多家网店系统的功能,加以优化。6、支持三种类型的数据库:Acces
- 单列索引(适合软删除比例高、常需查有效数据的场景):
INDEX idx_deleted_at (deleted_at) - 联合索引(如常按状态+时间查):
INDEX idx_status_created (deleted_at, created_at) - 注意:MySQL 中
IS NULL可走索引,但部分旧版本对函数索引支持有限,避免写成IFNULL(deleted_at, '1970-01-01')这类表达式
业务层需统一拦截“未删除”条件
避免每个 SQL 都手动写 WHERE deleted_at IS NULL,应在 ORM 或 DAO 层做默认过滤。
- 例如 Laravel 的 Eloquent 支持
SoftDeletestrait,自动追加全局作用域 - MyBatis 可通过拦截器或 BaseMapper 封装通用查询条件
- 显式查含已删除数据时,应使用明确命名的方法,如
findWithDeleted()或传参includeDeleted: true
慎用布尔字段 is_deleted
虽然简单,但存在语义歧义(比如初始值设 true 还是 false?逻辑反转易出错),且无法记录删除时间,后续扩展性差。
- 若必须用布尔型,务必设默认值为
FALSE,并确保所有插入不显式赋值 - 索引效果不如时间戳(MySQL 对低基数布尔字段索引效率较低)
- 不建议在新项目中首选,仅用于遗留系统兼容或极简场景
deleted_at 当作一等公民字段对待,从建表、索引、查询到业务逻辑层层对齐,才能真正落地可靠。









