删库跑路系列-------清理线上订单数据

一。问题由来

历史订单详情表order_detail 出现大量脏数据,大约10kw行,

存在数据原因在于,order_detail表的主键order_detail_id用的是UUID【此处不是原始的业务问题哈,是仿效说明问题,而已了(UUID是通过java程序生成,不是数据同步等)】

,再重复导入数据时会保证数据不重复,这就造成在查数据大量重复: 

order_price<sum(price)

需要对订单详情表数据进行处理,并且在订单详情表增加付款人ID字段,修改订单详情表的order_detail_id

订单表:order

 原始订单表:order_detail

 

需要更新的:order_detail

 

二、解决方案

1、因为订单详情表的数据量很大,所以需要将数据提取一部分处理,进行更新:10w条一次

方法一:使用with语句

with test as
(
select v1.*,o.user_id
from 
(
select order_detail_id,
order_id,
product_num,
unit,
price,
create_time
from order_detail
where user_id is null 
limit 100000
)v1
inner join order o
on(v1.order_id=o.order_id)
)
--update语句就不写了,根据自己数据库需要写吧
update order_detail set user_id = '' 
where order_detail_id in (select order_detail_id from test
);

因为我们用是阿里的ADB For Mysql 3.0(2021年1月8号,要严谨一些的,阿里数据开发人员告诉做,update 用不了inner 语法),不支持这种写法,只能逼着本人,用另一种方案解决了。

哎:

方法二:拆分sql进行执行

步骤一:
truncate
table order_detail3; 步骤: INSERT INTO order_detail3 select v1.*,o.user_id from ( select order_detail_id, order_id, product_num, unit, price, create_time from order_detail where user_id is null limit 100000 )v1 inner join order o on(v1.order_id=o.order_id) ; 步骤三: DELETE FROM order_detail WHERE order_detail_id in (select order_detail_id from order_detail3 ); 步骤四: INSERT INTO order_detail select MD5(concat(order_id,product_num,unit,price,user_id,create_time)) as order_detail_id, order_id, product_num, unit, price, create_time, user_id from order_detail3 ;

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

上面sql语句初看是不是没有问题那?

 

单单从sql的层面来说,其实上面的sql语句是有大问题的,而且有大问题:不服看代码

 

步骤一:
truncate table order_detail3;
步骤二:
INSERT INTO order_detail3
select v1.*,o.user_id
from 
(
select order_detail_id,
order_id,
product_num,
unit,
price,
create_time
from order_detail
where user_id is null
)v1
inner join order o
on(v1.order_id=o.order_id)
limit 100000 ;
步骤四: INSERT INTO order_detail select MD5(concat(order_id,product_num,unit,price,user_id,create_time)) as order_detail_id, order_id, product_num, unit, price, create_time, user_id from order_detail3 ;
步骤三:
DELETE FROM order_detail WHERE order_detail_id in (select order_detail_id from order_detail3 );

上面代码改了两处,

其一:是limit100000 的位置,

其二是,步骤三和步骤四的位置

其一原因是,当表order_detail 表中存在order_id 为空的数据的时候是好导致整个SQL,无法做到清理数据的目的,所以要将limit 10000放在外面

其二原因是,程序是循环执行的,10分钟一次,程序的稳定性,加入数据在指向完步骤三之后突然程序死掉了(链接时长啊,等等莫名其妙的问题),后续数据没有插入进去,10分钟之后,执行步骤一,是不是要删库跑路了啊

 

三、执行过程

执行过程,一定要有监测功能,如果用python,或者shell脚本调用程序,10分钟一次,

 

 

 这是还要建一个自依赖,保证任务在执行完之后,才执行下一个任务,如果:如果一个任务没有跑完,另一个任务开始truncate 了,这就又是要删库跑路了啊,

 

 

 上图是建立自依赖关系(线上数据库吃性能啊,频繁的读写,会导致SQL执行时间过长)。

 

其实上面的,sql执行语句还有优化的空间,

你还有什么更好的解决方案啊,欢迎交流,

 

posted @ 2021-01-08 19:24  小南天门  阅读(124)  评论(0编辑  收藏  举报