jdbc 执行批量 update 的效率问题

2023-11-27 08:38:53 +08:00
 qee

最近客户要对数据库存储的数据做国密改造,提供了相关的加密 sdk ,原来的数据库表存储的数据要升级成密文。 现在就想用原生的 jdbc 读出数据原文加密后存再进去,但是执行 batchexecute()的方法一次 1000 条,发现巨慢,按我查到都是推荐批量更新,但我这个就是巨慢。然后搞了测试表,结构里的索引什么的都删了还是慢。 数据库情况:postgre ,单表有 100+W 的数据,加密更新四五个字段 代码大致:

    connection.setAutoCommit(false);
    PreparedStatement preparedStatement = connection.prepareStatement("update users set name = ? where id = ?");

	for(int =i;i<res.length;i<1000){
    	preparedStatement.setString(1, "John");
    	preparedStatement.setInt(2, 1);
    	preparedStatement.batchadd()
    }
    

    preparedStatement.executeBatch();
    connection.commit();
    

这个哪位有好的优化思路吗,或者别的方案

2826 次点击
所在节点    数据库
29 条回复
lqw3030
2023-11-27 08:45:42 +08:00
整个表读出来改(高性能机器/分布式计算),改完写到 table_modified,然后重命名下表
ZhanXinjia
2023-11-27 08:48:21 +08:00
这么搞肯定慢。
第一点:不要用框架,框架比较耗时,直接用 jdbc 手写 sql 注入。(要看国密是否有转移字符问题,如果没有直接注入)
第二点:换一个方式写 sql ,做临时表 m:
就是把你之前这样的语句:
begin;
update t1 set c2=2 where c1=1;
update t1 set c2=3 where c1=2;
update t1 set c2=4 where c1=3;
update t1 set c2=5 where c1=4;
update t1 set c2=6 where c1=5;
commit;
优化成:
UPDATE t1 m, (
SELECT 1 AS c1, 2 AS c2
UNION ALL
SELECT 2, 3
UNION ALL
SELECT 3, 4
UNION ALL
SELECT 4, 5
UNION ALL
SELECT 5, 6
) r
SET m.c1 = r.c1, m.c2 = r.c2
WHERE m.c1 = r.c1;
第三点:多线程干。
ZhanXinjia
2023-11-27 08:49:32 +08:00
之前做过类似的加密,一分钟可以加密 50 万条左右
cubecube
2023-11-27 08:57:46 +08:00
id 上的索引你得留着呀
wwwz
2023-11-27 09:00:05 +08:00
之前好像搞过,用 replace into 效率比较高
akira
2023-11-27 09:07:10 +08:00
加密 ,更新 分别耗时多少。
so2back
2023-11-27 09:10:38 +08:00
试试 update case when 的写法,拼一条语句更新 2000 条记录,前些天用 mysql 试过,1 分钟可以更新 100w
xiwh
2023-11-27 09:27:58 +08:00
慢的主要原因是你没提前开一个事务, (貌似 pgsql 关了自动提交,executeBatch 每条语句都是一个独立的事务),所以执行前可以提前开一个事务
还有两种更快方案:
依然还是用 batchexecute
1. 基于 pgsql INSERT...ON CONFLICT DO UPDATE (主键冲突则更新)实现批量更新
2. 复制一张表,在这张表的基础上批量插入,执行完了再把名字改回去(相比第一种更快)
qizheng22
2023-11-27 09:33:10 +08:00
在连接加上:rewriteBatchedStatements=true
BBCCBB
2023-11-27 09:57:02 +08:00
楼上说了 加 rewriteBatchedStatements 参数
kaf
2023-11-27 10:07:07 +08:00
写临时表然后重命名
150530
2023-11-27 10:11:36 +08:00
@ZhanXinjia 第二点的这个 UPDATE 是什么写法,有点看不懂啊
liprais
2023-11-27 10:13:28 +08:00
接口是接口,实现是实现
mringg
2023-11-27 10:15:33 +08:00
话说只给了部分代码不好分析,还是得统计下每一部分的时间,在做调整。
1. 每次只查询 1000 条数据的时间
2. SM 算法每次只加密 1000 条数据时间
3. 每次只更新 100 条数据的时间
ZhanXinjia
2023-11-27 10:25:30 +08:00
@150530 就是用你原始的 id (唯一索引)和更新的结果(加密后的字符串)用 union all 拼接成一个临时表,然后根据原始表和临时表有一样的 id 来一一对应起来更新。
kestrelBright
2023-11-27 10:29:10 +08:00
楼上说了加 rewriteBatchedStatements 参数
150530
2023-11-27 10:32:32 +08:00
@ZhanXinjia 懂了懂了 UNION ALL 组虚拟表学到了
matepi
2023-11-27 10:36:09 +08:00
insert 一张空表效率先看看?
如果空表效率可以,那么就可以 insert 完,再做联表 update
如果空表效率不可以,说明本身 batch 形式用法还存在问题
litchinn
2023-11-27 10:49:11 +08:00
postgresql 有 rewriteBatchedStatements 参数吗
cnoder
2023-11-27 11:30:19 +08:00
直接 update 吗,不应该是先双写嘛

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/995403

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX