数据的软删除和物理删除

前言

不同的业务数据的删除需要不同的策略,一些需要永久保留,一些可以直接删除。

关系型数据

关系型数据库里面,一条记录的删除,根据业务需要,很大可能选择软删除,因为:

  • 数据完整性,相关数据可以保留
  • 历史数据查询,方便审计等
  • 速度快

因为删除一条被外键引用的数据,数据库系统会遍历相关数据,确保没有被引用才删除,所以有可能很慢,譬如用户表,一般会被大量业务表引用,物理删除用户可能会超时。

举个具体例子,一个商城,如果下架一个商品,不会做物理删除,因为所有历史订单、收据、报表等等都要层级删除,那严重破坏数据完整性。

又或者员工不爽,离职了,如果物理删除这个员工的记录,那所有和ta相关的数据都要被删除,那是不合理的。

所以这里,很多时候,不是做“删除”,而是做状态改变,所以我们称之为“软删除”。

时光机

另外,总会有手贱/失误的时候,如果要让DBA去找历史数据回来修复,那系统功能受影响的时间就受限于DBA了。

另外,关于数据有效性问题,历史数据未必是最新的,老数据一些时候比没有数据更糟糕。

软删除是后悔药,大大降低了损失的可能性。毕竟,你永远不知道哪天你又需要那条被删除的记录了。

坑s

当然,这样会带来几个问题。首先是有效数据的过滤问题。譬如现有的的用户列表逻辑,需要去掉被标记为删除的数据。这种情况,要么做个视图,要么逻辑加入过滤条件。

如果对标记字段(譬如IsDeleted: bool 或者Status: int),一般没有很好的entropy,所以不是很好的候选索引字段,但是我们可以做筛选索引(filtered idnex)来解决。

另外,需要考虑唯一主键,因为之前同一个业务只有一条记录,现在可以有多条(1条有效,n条被删除)。譬如用户表,软删除了用户Foo,那以后注册的用户就不能用Foo这个名字了。这种数据冲突比较麻烦,所以这样会对业务逻辑增加难度。

还有,数据不被物理删除,随着时间推移,会累积越来越多的数据,这个可能会带来几个问题:

  • 空间增加
  • CRUD速度下降(索引相关)

人工审核

有些公司有一定的流程,专人对被标记擅长的数据进行审查,确认这个数据是否真的应该被删除。

定时物理删除服务

其次,可以实现一个定时服务,在系统空闲的时候,删除那些被标记了的数据。

除了现有表做标记的软删除,其他做法如不原表留下,转到历史表,不过这种情况下外键约束就有层级关联问题要解决了,除非完全不用外键约束。

当然,除了历史表,还可以写到其它数据存储结构,譬如NoSQL等。

触发器

如果不写定时服务,可以考虑即时的表删除触发器,一般关系型数据库系统提供这个功能,当一条记录被删除的时候,会调用你定义的删除触发器逻辑,在这个触发器里面,你根据业务需求做各种操作,譬如把数据挪到历史表等。

数据保留期限

视乎具体业务需求和合规性要求,被标记软删除的数据,保留时间可以从1天到永久都有可能。

非关系型数据

非关系型数据库天生没有这种强约束的优势/烦恼,可以直接物理删除。

数据的安全

数据的保护和加密会在另外一篇文章详细讨论。

即便物理删除,我们也需要考虑,如欧盟的GDPR和一些国家的Privacy Act要求之前的数据备份也是需要删除的,这就对冷备份的数据有挑战了。

数据策略

总而言之,不同的公司不同的业务应该有不同的删除/保留/备份/安全策略,不能一概而论。数据管理的最终目标:

  • 准确性
  • 完整性
  • 安全性
  • 合规性
  • 性能

性能重要,但不是最重要的。关于性能,我对后端、数据库、云、整体架构有多年的实战经验,有兴趣的同学可以扫描右边二维码加我讨论。

版权所有

所有文章内容版权所有,任何形式的转发/使用都必须先征得本站书面同意。本站保留一切追究的权利。

大量报表的生成优化办法

前言

一个页面,加载耗时1.3分钟,分析后发现用的O/RM,我记得12306以前爆是因为用的hibernate,而且没用好。

O/RM有各种硬伤,但总是有优化办法。我改进后测试1秒。

痛点

澳大利亚很多政府/企业财年结束(6月30日)便需要进行一些年度操作,譬如给客户发送年度报告等等。

澳大利亚最大的养老金管理也不例外,需要给数百万用户发送一个流水账单(PDF文件格式),根据多年来的观察和官方的说明,一般需要等到9月底到10月初,这意味着需要起码2个月来处理。

分析

简单计算,意味着顺序处理的话,大概每秒完成一个客户,听起来不算慢。

大家会觉得,一年的流水,多则几百条记录,取出来0.4秒,生成PDF是0.5秒,发送0.1秒,那相当合理。

在这个系列操作中,单个业务的瓶颈可能是:

  • 数据获取/计算
  • PDF生成
  • Email发送

优化

最佳的优化,彻底理解业务逻辑后作出相应的改动。在没有理解业务逻辑之前,我们一般提供效率的做法可能有:

  • 分而治之:多个服务器并行操作,每个负责某个用户组,譬如如果有10台机器,那机器1可以处理10%,如此
  • 队列异步:数据获取/计算、生成PDF和Email都分开队列,异步处理,这样每一步的操作不会因为其中一部堵塞后续的操作
  • 内存操作:PDF生成无需写入磁盘再作为附件发送出去
  • 外部资源:邮件发送可以使用第三方的支持异步的服务,譬如Sendgrid,除了独特的功能之外,我们需要的是无阻塞的异步高性能操作

关于数据获取/计算,如果要做优化,可以在设计上做一些改动,譬如加入每月统计,这样到财年末的时候只需要统计过去12个月的月统计便可。而且这些流水如账本那样,只会append only,不会对现有记录进行改动,所以无需考虑重新统计。

另外,单数据库会是性能(还有安全)瓶颈,完全可以把流水/统计数据放到多节点NoSQL里面,取的时候性能优于关系型数据库。

 

当然,还有一些更高级、复杂的优化实践,有兴趣的同学们可以根据右边二维码加我的微信。

 

想知道为什么我这么多年来能掌握那么多种技术,不仅仅是广度,还有深度,达到我所说的“爆栈”吗?

在《爆栈之旅》,我根据大家都实际情况、水平、方向等规划职业路径,手把手带你做实战的项目,用最高效的办法达到你想要的高度。

爆栈之旅

是否想技术水平快速提升?是否希望快速成为公司的技术骨干?

核心价值
  • 把我这10多年来所学到的知识、总结的经验、吸取的教训分享出来
  • 针对不同的学生量身定制规划学习成长路线、1对1个人指导、代码审阅等
  • 解答各种技术问题
  • 为公司提供技术解决方案

请查看本站右边的信息联系我。

版权所有

所有文章内容版权所有,任何形式的转发/使用都必须先征得本站书面同意。本站保留一切追究的权利。

爆栈思想 – 怎么样才算是某个领域的专家

我们发现,很多简历充斥着各种“精通”,尽管刚毕业不久,没有多少实际项目经验。

 

究竟怎么样才算是某个领域的专家呢?

 

应该分几方面看:
  • 技术深度
  • 影响力
  • 对社区的反哺/贡献
譬如数据库存储这块,拿SQL Server做例子,应该掌握以下技术的原理、解决办法和最佳实践:
  • 数据类型/对象
    • 各种数据类型的转换优先级、差异
      • 看似简单,举2个例子:
        • SELECT 1 + ‘+’ + 1
        • 4种不同的临时表/表类型差异和最佳实践
  • 访问
    • 各种DDL/DML/DCL/TCL的最佳实践
  • 内核机制
    • 调度器
    • 各种hint
      • 升级、优先级和差异
      • 堵塞
      • 死锁
    • 等待/延迟
    • IO Stall
    • 进程/请求/任务/连接
    • 缓存/缓冲
  • 最大限制与版本差异
    • 各种级别/方面的最大/最小限制
    • 不同版本的差异
    • 不同版本的新特性、失效特性
  • 深入排错
    • 错误的级别和哪些会在客户端触发
    • 排错的多种方式
  • 调优
    • 表、列设计的最佳实践
    • 索引、扫描、各种Lookup、Bookmark
      • 各种类型的索引的差异
      • 性能相差数万倍的设计
      • 索引管理最佳实践
    • 执行计划
      • 如何找到性能瓶颈
      • 编译、损坏与修复
      • 如何强制刷新(多种方法和副作用)
    • 不同方法的性能巨大差异
      • 譬如COALESCE vs FOR XML vs STRING_AGG
    • 利用多核的最佳实践
    • 数据库/日志文件切分、存储的最佳实践
    • 数据库/日志备份/恢复的最佳实践
    • 内存调度最佳实践
    • 内联
    • 各种trace flags
  • 海量数据处理
    • 高效分库分表
      • 各种切分的优缺点
    • 如何实现大量数据的导入和导出
  • 安全和访问控制
    • 如何实现实例、数据库、表、行、列多级访问控制
    • 如何防止注入和入侵
    • 跨库访问的最佳实践
  • 审计和记录
    • 审计的最佳实践
    • 如何高效实现修改操作记录
  • 容灾、高可用最佳实践
    • AlwaysOn / HAG
    • 如何fail over
    • 备份的多种方式、差异和最佳实践
  • 扩展
    • SQL CLR
  • 管理/自动化
    • 任务
    • DMV
    • DBCC
  • BI
    • SSIS
    • SSAS
    • SSRS
如果详细写下来,这会是一本《SQL Server专家》。

 

关于影响力、对社区的反哺和贡献,这主要是看是否参与社区的讨论/问题解决、代码贡献等。

 

 

想知道为什么我这么多年来能掌握那么多种技术,不仅仅是广度,还有深度,达到我所说的“爆栈”吗?

在《爆栈之旅》,我根据大家都实际情况、水平、方向等规划职业路径,手把手带你做实战的项目,用最高效的办法达到你想要的高度。

爆栈之旅

是否想技术水平快速提升?是否希望快速成为公司的技术骨干?

核心价值
  • 把我这10多年来所学到的知识、总结的经验、吸取的教训分享出来
  • 针对不同的学生量身定制规划学习成长路线、1对1个人指导、代码审阅等
  • 解答各种技术问题
  • 为公司提供技术解决方案

请查看本站右边的信息联系我。

版权所有

所有文章内容版权所有,任何形式的转发/使用都必须先征得本站书面同意。本站保留一切追究的权利。

爆栈思想 – 数据库“状态”字段如何设计

前言

之前在文章《学员问答精选 – 1 – 数据库表拆分》中提及过一个数据库的设计问题。今天,微博上的@火丁日记 说:

表里有一个 status 字段,用来表示数据的状态,比如订单的已付款,已关闭等。以前我习惯把它定义为 INT 类型,但是慢慢的,我就记不清楚 1,2,3 到底指的是什么意思了,也想过用 ENUM 类型,但是不方便扩展,最后,我觉得直接用 VARCHAR 类型算了,去它的三范式。

百家争鸣

  • 一些网友赞同使用varchar
  • 一些还是觉得应该enum
  • 一些觉得最原始的int是最好的
  • 一些觉得要用字典表

各种考量

其实,一个字段类型的考量,主要包括:

  • 准确性/精确性:必须能满足业务需求,不能丢数据,溢出等
  • 性能:一般来说,int的运算比varchar要快
  • 空间:尽可能占用最少的空间,一条记录浪费1字节,10亿记录就浪费1GB空间了
  • 辅助性:譬如方便功能上的排序、方便开发人员记忆等

如果要为开发人员着想:

  • 数据库里,表的字段可以添加描述,譬如0: Pending, 1. Paid, 2: Processing, 3: Delivered, 4: Cancelled
  • 如果不满足,那可以用char(1),26个字符足够表达各种状态了吧?不够就char(2),再不行就char(3),主要是省空间。为什么不用varchar(n)而用char(固定数值)?因为varchar(n)要运算做各种trimming,起码在SQL Server里,譬如len()就是后面空格去掉后的长度,和datalength()不一样。这个一般是单词的首字母,记起来比int舒服些。我发现一些公司就是这样做的。

如果要追求节省空间,完全可以用tinyint甚至varbinary,毕竟1个字节有8位,一般订单也就那么几个状态吧?

首先,如果用varchar,那么要考虑:

  • 你这个状态的值,是放英文还是中文?你的产品是否全球化的?
  • 如果是放英文,那你还是需要本地化。
  • 而且,既然要本地化,就没必要放完整的单词,char(1)便可,原因参考上面。

如果使用int,那么要考虑:界面文本显示,开发人员友好。

如果要考虑界面显示如排序等,一般来说,界面需要先根据条件过滤出来某种状态,但是,如果你的业务逻辑就是要同时显示多种状态的数据,这要考虑目标数据只是已经在界面的,还是在数据库的:

  • 界面:那数据库的类型还是最精简的varbinary(1),在界面对值进行解释然后根据解释出来的规则进行排序

当然,有些业务系统会使用字典表,相当于外键,如果返回结果的时候就join,这里会比case xx when 1 then ‘某状态’ 的效率要差些,而且字典表还是需要做语言本地化的。

总结

其实,不管用哪种方案,都没有完美的,还是应该具体业务需求来。

 

爆栈之旅

是否想技术水平快速提升?是否希望快速成为公司的技术骨干?

核心价值
  • 把我这10多年来所学到的知识、总结的经验、吸取的教训分享出来
  • 针对不同的学生量身定制规划学习成长路线、1对1个人指导、代码审阅等
  • 解答各种技术问题
  • 为公司提供技术解决方案

请查看本站右边的信息联系我。

版权所有

所有文章内容版权所有,任何形式的转发/使用都必须先征得本站书面同意。本站保留一切追究的权利。