蔡良呈
发布于 2023-11-10 / 0 阅读 / 0 评论 / 0 点赞

数据摆渡过程问题记录

记录数据摆渡过程中大数据测试暴露出的问题

背景:A库数据明细数据状态同步到B库,因网络安全等因素限制,使用数据摆渡方式,

主要服务涉及:A前端页面+A后端服务+A数据库 和 B前端页面+B后端服务+B数据库

原始过程:

1.先将A库中需要同步的数据查询到A后端服务器上

2.A服务器上拼接出数据摆渡sql(即用于B库更新的sql)并写入多个到.txt文件中,

3.A服务器上将所有本次的.txt文件打包为zip压缩包并上传到文件服务器

4.A前端页面获取文件服务器上的压缩包

5.用户拿这个压缩包到B前端页面,导入压缩包

6.B服务器获取压缩包,读取压缩里的.txt文件内容,获取sql语句,对B数据库指向sql语句更新数据。

随着数据量增大到千万级,暴露出一下问题:

1.过程12出现的内存溢出问题,需要更新的数据量达到千万。 解决方案:分批获取数据,每批获取后需立即写入到磁盘文件中

2.过程3,因文件太大,如果直接上传会出现超时等问题。解决方案:文件上传需要使用分片上传

3.过程5,与过程3同理,导入使用分片上传

4.过程6,获取压缩包内容要先一点一点放到硬盘中,直接放到内存中会导致内存溢出。

一下是6过程中出现的批量数据更新问题及解决过程:

执行sql需批量执行,原版中有个sql,一条sql语句直接更新数据量达到千万条,因为mysql是主从复制,结果直接先抛出binlog缓存溢出。

原sql:update supplier_item_basis_condition s LEFT JOIN base_condition b on s.condition_id = b.id set s.match_flag = 0 WHERE s.project_id = 1722068063492304896 and s.match_flag = 0 and b.env = 1

解决方案:批量更新,第一个想法是在update语句后面拼接上limit,但是语句中关联了另一张表进行过滤,且mysql版本为5.7.22(本地8.0支持),直接抛出 incorrect usage of update and limit

后来各种搜索+询问chatGpt都说使用了in的临时表:于是改成了下面这样

UPDATE supplier_item_basis_condition

SET match_flag = 2

WHERE id IN (

SELECT id FROM ( select s.id from supplier_item_basis_condition s LEFT JOIN base_condition b on s.condition_id = b.id WHERE s.project_id = 1722068063492304896 and s.match_flag = 0 and b.env = 1 limit 1000 ) AS temp

)

但是这个更新太慢了,主要是用了in子查询,而且还是直接加了表锁,导致其他事务对这两张表的增删改语句都一直超时。

目前方案:后面暂时改为先批量查询出supplier_item_basis_condition 符合数据的id,再批量更新。

还有一种方案:使用exists,语句上没问题,但是不知道会不会出现其它问题

UPDATE supplier_item_basis_condition s SET s.match_flag = 2 WHERE s.project_id = 1722068063492304896 and s.match_flag = 0 and EXISTS (select 1 from base_condition b where s.condition_id = b.id and b.env = 1) limit 1000


评论