逻辑删除还是物理删除

逻辑删除还是物理删除看到标题,有的童鞋心中暗想“数据删除有什么可提的呢?不就是执行个delete语句吗?有什么难的呀?”其实呢数据删除没有你想的这么简单,一般情况下公司会明确的要求数据只能逻辑删除,不能物理删除。那什么优势逻辑删除,什么又是物理删除呢?物理删除就是我们之前常用的DELETE、TRANCATE、DROP语句删除数据,不管你用哪种方式,都是将数据从硬盘上抹除,这样数据表的体积就变小了,数据的读写性能就提上去了。有个共识InnoDB引擎的数据表记录一旦超过2000万,它的读写性能就很差,我们用物理删除能缩小表

大家好,又见面了,我是你们的朋友全栈君。

看到标题,有的童鞋心中暗想“数据删除有什么可提的呢?不就是执行个delete语句吗?有什么难的呀?”其实呢数据删除没有你想的这么简单,一般情况下公司会明确的要求数据只能逻辑删除,不能物理删除。那什么优势逻辑删除,什么又是物理删除呢?

物理删除

就是我们之前常用的DELETE、TRANCATE、DROP语句删除数据,不管你用哪种方式,都是将数据从硬盘上抹除, 这样数据表的体积就变小了,数据的读写性能就提上去了。
有个共识InnoDB引擎的数据表记录一旦超过2000万,它的读写性能就很差,我们用物理删除能缩小表的体积,提升读写性能,这挺好的,原则上也是这么一个道理,但是物理删除数据的代价你了解吗?

物理删除的代价一

由于物理删除是真的被删除的,当我们发现数据是被误删除的,那么恢复起来是非常困难的,恢复数据还要停掉数据库,对业务系统的影响是非常大的,所以误删除的后果是非常严重。

我有一个在携程网工作的DBA朋友,他说“如果那里的数据出了问题,停机维护成本还是挺大的,因为好多人都用携程app来买机票跟酒店” 他以前跟我说过一次,携程网停机一小时损失差不多是在一两百万的情形,如果业务系统停机还好说,因为业务系统都是分布式集群的部署的,前台系统和后台系统分别部署在不同的节点,挂掉几个对整体影响也不是很大。但是别看数据库也在搞集群,但是数据除了问题那么可是所有的MySQL节点要停机维护的,业务系统没有了数据库还运行个什么劲呢?所以数据库的运行可靠性是非常重要的,不能出现一丁点儿事儿的。

那么数据库误删除是怎么发生的呢?比如说,小王在程序里写了一个带有bug的delete语句,平时这个sql语句运行还算正常,但是传入特殊的数据导致bug运行,就会误删除很多的数据,这样的结果真的是非常严重。如果误删除了数据,有什么办法恢复数据吗?当然有了,如果误删除了数据,需要停掉数据库才行,对业务系统的影响是非常大的。

具体的执行时这样的:
在这里插入图片描述

平时我们数据库在执行SQL语句的时候是这样的,这些操作记录在binlog日志里面,恢复数据的时候,你们编写程序提取binlog日志里面的内容然后逐条分析,看看是那一条sql语句导致的误删除,导出binlog日志里面的sql语句,当然了这些sql语句里面是不包含误删除的那条sql语句,因为我们把它给抠掉了,接下来启动数据库,清空数据表里的所记录,然后把这些sql语句重新执行一遍,就相当于把以前的增删改查又执行了一遍,这样数据就恢复了。

除了这种方式外,还有一种恢复数据库的办法,那就是为MySQL配置延迟删除节点,也就是再弄一个MySQL数据库,让这两个数据库做延迟同步数据,当一个MySQL出现了误删除,因为有延迟同步,比如说延迟24小时数据再同步,也就是再24小时内,都可以从第二个MySQL节点来同步数据,然后恢复到第一个MySQL节点上面,这也是恢复删除的办法,像这些开脑洞的方法,在MySQL集群PXC方案都有

物理删除的代价二

会让数据的主键值变的不连续,不连续的主键值会让分页查询的速度变慢。我们看下面例子

正常的分页查询语句会在select语句后面加上Limit

SELECT ... FROM ... LIMIT 1000,20 ;

我想从1000条数据中取20条记录,这个语句就写成了limit 1000,20 ,那这条sql执行的时候,数据库可要从第一条计数,数到1000条的时候,开始往后查询20条数据,当然我现在要想查询10万条以后的数据, 数据库就得从头计数,从第一条数到10万条记录,然后再往后查询你想要的数据,越是数据越多,这个limit后面你所要查询的就越慢,所以我们要像一个办法去解决分页查询的问题。

于是我们想到了利用主键字段加速分页查询的办法,这个分页查询就写成了这个样子

select ... from ... where id>=1000 and id<=1020;

因为主键是自带索引的,索引就是对字段进行排序,那么查询的时候可以快速跳过很多的数据,直接定位到我们想要的数据,像英文词典,如果想要查找Object这个单词,直接就可以定位到O开头的单词去小范围的查找,这样就加快了查询的速度。如果英文单词的排序不是按照首字母排序,我查找Object的时候就得从第一页翻到最后一页,非常的耗时。
那我们再来看id>1000这个顺序,因为主键是按照顺序排序的,索引数据库可以很快的定位到id=1000这样的记录,查询的速度是非常快的,后续的查询也是做的这么个二叉树的查找,所以用主键去做分页查询的条件,个查询的速度比limit子句快的多。

但是现在有个问题,如果我们对数据做了物理删除,这个主键就变成不连续的了,也就是意味着利用主键来分页查找是不行的,因为从1000到1020这个主键范围之间可能只有几条数据而不是完整的20条记录。

这就是物理删除的第二个代价,没有办法用主键这种加速分页查询了。当然了,在一些必须要物理删除的情形下,还是有折中的加速分页查询的方法

什么样的数据不适合物理删除

核心业务表的数据不建议做物理删除,因为物理删除后,真的就只能停机恢复数据,这个代价真的非常大,反之我们可以对需要删除的记录做状态上的变更,而不是非要删除它们,这就是逻辑删除的原理

我们看下例子,给作废的订单设置为作废的状态,给注销的订单设置为注销的状态,给过期的优惠券设置为过期的状态,这都是可以的。
当然,有童鞋会说“如果表里存放了大量无效的数据,这个会占用表的空间,那么Innodb这种引擎,一张表的数据超过2000万性能就会下降的很快,那么用逻辑删除表是不是就会增长的很快呢?”,这种问题问的非常的好,这是童鞋是认真思考了,这个问题可以很优雅的解决,那就是再创建一张数据表历史表,这个表专门用来保存无效的数据,并且这个表还可以使用mongodb数据库,因为逻辑删除的数据重要性并不是那么高,主要保存下来即可。

最后来说下逻辑删除

  • 其实刚才我们已经知道逻辑删除的原理了,我们可以给表添加一个字段(is_deleted),标记该字段已经逻辑删除,我们在查询数据的时候在where子句上加上is_deleted=0那么查询出的就是那些没有被物理删除的记录了

    select ... from ... where is_deleted=0;
    
  • 核心数据表一定要采用逻辑删除,而不是物理删除
    像订单表、商品表都要采用逻辑删除。上面说把逻辑删除的记录都放到历史表,不就可以不用给数据表添加is_deleted字段了吗?
    不是多次一举,如果平时我们的数据库系统都是满负荷的工作,数据迁移这种工作我们可以放到后半夜去做,那样的数据库的负载比较低,我们给数据库设计了is_deleted字段后,标记了那些数据是要殴删除的,通过编写一个定时器程序,把要删除的数据转移到历史表,这样不是挺好的吗?也就是白天业务表还是要缓存一些逻辑删除的数据,等到后半夜我们再做系统的迁移。

我们给t_user表做逻辑删除

  1. 创建历史表的sql语句:

    create table t_user_history LIKE t_user;
    
  2. 添加一个is_delete字段

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/137063.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java finalize方法使用

    Java finalize方法使用《JAVA编程思想》:java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。         (1).对象不一定会被回收。      (2).垃圾回收不是析构函数。      (3).垃圾回收只与内存有关。

    2022年9月19日
    3
  • ibatis isNotEmpty

    ibatis isNotEmpty1、ibatis中isNotEmpty的作用        selectxiddictCode,xnamedictNamefromcity  ]]>                  xflag=$xflag$   ]]>                              xprovince_id=#xpro

    2022年10月7日
    2
  • 美军打掉德国炮兵阵地的电影_英雄连2怎么找炮兵阵地

    美军打掉德国炮兵阵地的电影_英雄连2怎么找炮兵阵地司令部的将军们打算在 N×M 的网格地图上部署他们的炮兵部队。一个 N×M 的地图由 N 行 M 列组成,地图的每一格可能是山地(用 H 表示),也可能是平原(用 P 表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响

    2022年8月9日
    5
  • 数据库中什么是变量名_数据库表名命名规范

    数据库中什么是变量名_数据库表名命名规范codeIf简介:Github开源项目特点:1,支持中文;2,变量命名:Github,Bitbucket,GoogleCode,Codeplex,Sourceforge,FedoraProjec的项目源码3,可以查询代码片段及其代码库链接:http://unbug.github.io/codelf/举个例子查看代码查看代码片段查看代码片段更多文章,请关注博客:http://blog

    2022年9月21日
    1
  • Promise原理实现[通俗易懂]

    Promise原理实现[通俗易懂]首先先看一下promise的调用方式:实现原理如下:详细解释如下:定义异步函数MyPromise,所以执行的函数也是MyPromise:首先看函数执行的方法:newMyPromi

    2022年8月5日
    4
  • 学习笔记:ssh远程连接root登陆失败,ssh双端口策略,xshell上传下载文件,服务升级备份包,

    学习笔记:ssh远程连接root登陆失败,ssh双端口策略,xshell上传下载文件,服务升级备份包,遇到无法进行ssh远程传输服务时候检查一下配置文件 vim /etc/ssh/sshd_config 中的permissRootLogin 是不是no 改为yes重启sshd服务即可ssh服务一般开两个端口一个默认22一个5222(避免远程关闭端口后断开连接,无法登录)XShell建立连接后rz命令上传文件到linuxsz命令下载文件到window对服务进行升级后建议打包两个文件,一个带有配置文件(用于没有该服务的机器的服务安装),一个不带配置文件(x,用于其他已有该服务.

    2022年8月11日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号