怎样在MySQL中设计支持逻辑删除且唯一索引不冲突的表

星强吖_6001

星强吖_6001

2026-10-04

355人浏览

原创

唯一索引需与is_deleted组合为联合索引,如(username, is_deleted),使已删与未删记录视为不同项;若历史数据存在多条同名已删记录,须先去重;也可改用deleted_at或主键id实现更灵活删除,但需配套查询条件和复合索引。

怎样在mysql中设计支持逻辑删除且唯一索引不冲突的表

唯一索引和 is_deleted 字段直接组合会出错

直接在 username 上建 UNIQUE INDEX,再加一个 is_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0 字段,看似合理,但插入同名新用户时必然报 [1062] duplicate entry 'xxx' for key 'idx_username'。原因很直白:MySQL 的唯一索引不区分 is_deleted 值,只要 username 相同,哪怕旧记录 is_deleted = 1,新记录仍被拦住。

用 (username, is_deleted) 建联合唯一索引是主流解法

这是最轻量、最可控、也最符合 MySQL 索引机制的做法。核心在于让“已删”和“未删”变成两个不同的索引项:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • 执行 ALTER TABLE user DROP INDEX idx_username, ADD UNIQUE INDEX idx_username_deleted (username, is_deleted);
  • 此时 (username='alice', is_deleted=0) 和 (username='alice', is_deleted=1) 被视为不同值,互不冲突
  • 业务语义依然成立:一个用户名最多只允许一条 is_deleted = 0 的活跃记录
  • 注意:如果表里已有历史数据,且存在多条同名但 is_deleted = 1 的记录,这条 ALTER 语句会失败(因联合索引要求整行唯一),需先去重或清掉冗余已删记录

把 is_deleted 改成时间戳或主键 ID 更灵活但有代价

当业务允许“同一用户名被反复删除/注册多次”,又不想手动清理历史已删记录,可以放弃二值标记,改用可变值:

  • 将字段改为 deleted_at DATETIME NULL,逻辑删除时设为 NOW();再建联合索引 UNIQUE(username, deleted_at) —— 因为 NULL 不参与唯一校验,未删记录天然满足唯一性
  • 或者用 MyBatis-Plus 风格:字段类型仍是 TINYINT 或 BIGINT,但删除时写入主键 ID(如 UPDATE user SET is_deleted = id WHERE id = 123),再建 UNIQUE(username, is_deleted) —— 每次删除都产生新组合值
  • 缺点:查询条件得写成 WHERE is_deleted = 0 或 WHERE deleted_at IS NULL,不能依赖 ORM 自动注入;索引体积略大;恢复删除时要小心覆盖原 deleted_at 值

别漏掉查询和索引的配套动作

光改索引不够,逻辑删除真正生效靠的是每一处读操作都带上过滤条件:

  • 所有 SELECT 必须显式写 WHERE is_deleted = 0,不能只靠应用层拦截——统计脚本、后台导出、DBA 直连查表,全可能漏
  • is_deleted 单独建索引没意义,但高频查询如 WHERE is_deleted = 0 AND status = 'active',建议建复合索引 INDEX(is_deleted, status),且把 is_deleted 放左边
  • 外键关联表若也走逻辑删除,关联查询时两边都要加 is_deleted = 0,否则 JOIN 出来可能是“已删用户 + 未删订单”这种无效组合
实际落地时,最容易被忽略的是旧 SQL 的全局扫描加固——上线前必须 grep 所有 SELECT FROM user,确认每一条都补了 AND is_deleted = 0。漏一条,就可能把已删用户当活人发短信、算佣金、推消息。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3983

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

851

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1029

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5821

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2763

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5800

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7701

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1050

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

912

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 178人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 283人学习