最近有研发小伙伴请教我一个问题,他有某张表需要删除大量的数据,只保留最近小部分(最近一个月,数据量大约在300W左右)的数据,要怎么搞?
然后我去看了下这表,5000W+数据,每个月以400W+左右的量在增长。这是记录用户每天参加活动的流水记录,数据需要即时查看,但流水型记录关心最近几天的数据即可。对!业务对这些数据确实是“喜新厌旧”。其实,删除历史数据,只保留最近一个月的数据,在此种条件下一般非常容易处理,其中一个比较简单的方法是,创建一张旧时表,将最近一个月的数据存至该表中,然后将表名更换。
比如数据库表名为: t1 , 相关的SQL如下:
create t1_tmp like t1 ;
insert into t1_tmp select * from t1 where time_condition > '2021-04-06' ;
alter table t1 rename to t1_back_date ;
alter table t1_tmp rename to t1 ;
此处,需要注意的有两点:
1. insert 执行的事务过大,可能会影响线上数据库的稳定;
2. 在执行过程中,表t1可能又新插入了数据,更改表名后,需要确定是否有新增数据;需要再一次将数据补齐。在补齐过程中,会有短暂的数据不一致(表已经插入了数据了,却需要后续的处理)。
针对问题1,可通过编写存储过程,或者相关的python或shell程序,将大事务分拆,进而避免因为数据库执行大事务而遇到各种各样的问题。
针对问题2,可检查表数据是否有新增,然后将相关数据重新插入至新表中。
然而在此处,我比较关心的,不是如何将数据"删除"掉,而是背后引发的一些思考。首先,一般MySQL存放的,是一些比较重要的数据,比如一些用户信息、配置信息,或者业务对事务有所要求的数据。但是在此处,将这些日志型数据存放于MySQL,是否有所不妥?这一次操作过后,难道过几个月后,又需要再作一次操作?若果当此种数据需要保留较长时间,不能进行删除时该如何处理?对数据进行分表分库?
对于此种“日志型”的数据,我们一般情况下是建议存放于MongoDB等NoSQL数据库中。这里以MongoDB为例。
为什么选择MongoDB?是因为考虑到以下原因:
1. 天然的自带分片集群功能,数据库集群扩缩容较方便;
2. 有良好的数据压缩性能,节省了磁盘存储空间;
3. 良好的性能与功能,俗称性功能 ^_^ ;
4. 相对于Clickhouse,ElasticSearch等列式数据,写入没有延迟。
当然,除了MongoDB外,在不同应用场景下,Clickhouse,ElasticSearch等会有它适用的应用场景,这里就不一一细说了。
在部分研发眼中,数据量过亿了,或者过千万级别了,就是"大表"了,需要优化了,需要对数据进行"分表分库"。其实,数据表大不大,除了看行数外,还要看列数,索引数等,数据文件大小等。而且,对数据库性能影响大不大,还需要看表的查询方式,即SQL的效率。若果查询没优化好,2000条的数据也可以数据库实例拖死。
对于某些研发,MySQL分表分库可能是解决"大表"所用得比较多的招式了。MySQL分表分库里第一条原则,我觉得是:能不用MySQL作分表分库,就不要用MySQL作分表分库。某些“大表”,优化访问它的SQL语句,主要磁盘空间等出现瓶颈,数据存放于单库MySQL中是没有问题的。若果数据量比较大,单库存放存在硬件资源不足的问题时,可考虑将其存放于MongoDB等NoSQL数据库中。
什么时候才用上MySQL的分表分库?
1. 数据量很大
数据量来个一天几百上千万
2. 只能是关系型数据库,需要用到其事务特性等。
综上,对于MySQL的大表,我们可以通过对其进行归档删除;使用其它NoSQL代替等方式对其进行优化。若通过数据库层面的优化不能满足我们的需求,或者性价比较低时。我们需要通过业务层面去优化,从而实现节省资源,事半功倍。