记录数据摆渡过程中大数据测试暴露出的问题
背景: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