数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍

1.什么是逻辑删除

所谓逻辑删除是指数据已经“不需要”了,可是并无使用delete语句将这些数据真实的从数据库中物理删除,而只是用一个标志位将其设置为已经删除。

2.为何须要逻辑删除

  • 防止数据误删除,不能找回数据;
  • 这些数据还具备必定的商业价值,好比用户的注册信息;
  • 虽然这些数据能够删除,可是这些数据还有关联数据,这些关联数据不能删除

对数据进行逻辑删除,能够保证数据的安全性和完整性。可是,逻辑删除也会带来的一些

3.问题:

  • 数据库表的数据冗余,致使查询缓慢;
  • 写sql进行数据处理时须要排除那些已经逻辑删除的数据,这就会致使sql复杂,容易出错,特别是涉及多表查询时;
  • 进行逻辑删除时,还须要考虑与之相关的数据怎么处理;
  • 还有,若是数据表的某个字段要求惟一,并强制约束,好比用户表中的登陆用户名字段,设计为逻辑删除的话,一旦有新的同用户名记录就没法插入。但若是不将该字段设置为惟一性约束的,那么在每次插入数据的时候,都需先进行一次查询,看看有无未(逻辑)删除的同名记录存在,低效率是一回事,并且在高并发的系统中,很难保证其正确性

4.逻辑删除如何设计

设计方案:在表中加一个字段deleted字段(入门级,不推荐

deleted字段的值为0表示数据未删除,值为1表示数据已经删除。

插入数据数据时,这个值默认为0。删除数据时将这个值设置为1。查询和更新数据时都将‘deleted=0’这个条件带上,只查询和更新没有删除的数据。

这个方案比较简单,可是会有些问题。好比说你表中的一个字段user_name设置了惟一性约束,可是若是你只是进行了逻辑删除的话,相同的user_name就不能进行数据插入了。

问题展示如下:

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第1张图片

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第2张图片

 数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第3张图片

 数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第4张图片

但若是不将该字段设置为惟一性约束的,那么在每次插入数据的时候,都需先进行一次查询,看看有无未(逻辑)删除的同名记录存在,低效率是一回事,并且在高并发的系统中,很难保证其正确性

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第5张图片

然而你的服务运行了一段时间后你仍是发现了数据库中存在 name = a 且 is_delete = 0 的多条字段,大部分是因为如下缘由(并发问题):

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第6张图片

5.解决思路:

方案一:不采用逻辑删除,直接物理删除

方案二:新建历史表

主表进行物理删除,同时将删除的记录保存到历史表中

方案三:取消表的唯一约束,同时引入redis来保证唯一约束

取消表的唯一约束,在项目中引入redis,通过redis来判重,新增时往redis set记录,删除时,删除redis记录

方案四:保留删除标记,同时新建一个字段delete_token,用UUID

为数据库添加新的一列delete_token,当某一条记录须要删除时,将该字段设置为一个UUID,将name、delete_token设置为惟一键,这样当is_delete=0时,delete_token保持一个默认值,可以有效地限制name惟一,当记录被删除时,因为delete_token是一个惟一的UUID,便能保证删除的记录不会被惟一约束束缚。

方案五:变更删除标记为时间戳

将删除状态不以0,1表示,而是以时间戳为值,然后将删除状态为与之前的唯一约束A重新组成唯一联合约束index(A、del_flag),删除时变更del_flag的时间戳。

方案六:保留删除标记,同时新建一个字段del_unique_key,用主键id    【推荐】

保留删除状态位,再新增一个字段del_unique_key,该字段默认值为0,字段类型和大小与主键id保持一致,同时与原先的唯一约束重新组成联合唯一约束index(A,del_unique_key),业务进行逻辑删除,变更del_unique_key的值为该删除行的主键id。

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第7张图片

 数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第8张图片

数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第9张图片

 数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第10张图片

 数据库唯一索引与逻辑删除标识冲突解决方案对比与取舍_第11张图片

 

6.方案的取舍

方案一得从业务的角度上考虑了,如果物理删除,对业务无损,那就无所谓了。方案二等于需要删除的记录的表都需要有历史表,如果仅仅是用来实现记录删除记录,感觉有点大材小用。方案三引入redis,虽然也可以解决问题,但是又额外增加复杂度,同时还得保证redis和数据库的一致性。方案四UUID会占用很大的空间,当需要批量删除时,要对每一条记录进行逐行删除。例如该表还有一个字段叫age,如今须要删除age > 18的记录,共有50条,在业务中,因为须要为每条的delete_token字段插入一个UUID,因此须要将其拆分为50条更新操做来进行。这样的代价显然很难接受。因此不推荐使用方案五和方案六其实实现的思路是一样,不过如果已经是在线上跑的业务,还是推荐用第六种方案,毕竟新增字段正常对已有的业务影响相对较小,如果是第五种方案,直接将标志位修改为时间戳,可能还会涉及改业务。如果是新增业务,第五种和第六种方案比较推荐。

你可能感兴趣的:(数据库,数据库,逻辑删除,mysql)