jdbc 执行批量 update 的效率问题

209 天前
 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();
    

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

2627 次点击
所在节点    数据库
29 条回复
lqw3030
209 天前
整个表读出来改(高性能机器/分布式计算),改完写到 table_modified,然后重命名下表
ZhanXinjia
209 天前
这么搞肯定慢。
第一点:不要用框架,框架比较耗时,直接用 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
209 天前
之前做过类似的加密,一分钟可以加密 50 万条左右
cubecube
209 天前
id 上的索引你得留着呀
wwwz
209 天前
之前好像搞过,用 replace into 效率比较高
akira
209 天前
加密 ,更新 分别耗时多少。
so2back
209 天前
试试 update case when 的写法,拼一条语句更新 2000 条记录,前些天用 mysql 试过,1 分钟可以更新 100w
xiwh
209 天前
慢的主要原因是你没提前开一个事务, (貌似 pgsql 关了自动提交,executeBatch 每条语句都是一个独立的事务),所以执行前可以提前开一个事务
还有两种更快方案:
依然还是用 batchexecute
1. 基于 pgsql INSERT...ON CONFLICT DO UPDATE (主键冲突则更新)实现批量更新
2. 复制一张表,在这张表的基础上批量插入,执行完了再把名字改回去(相比第一种更快)
qizheng22
208 天前
在连接加上:rewriteBatchedStatements=true
BBCCBB
208 天前
楼上说了 加 rewriteBatchedStatements 参数
kaf
208 天前
写临时表然后重命名
150530
208 天前
@ZhanXinjia 第二点的这个 UPDATE 是什么写法,有点看不懂啊
liprais
208 天前
接口是接口,实现是实现
mringg
208 天前
话说只给了部分代码不好分析,还是得统计下每一部分的时间,在做调整。
1. 每次只查询 1000 条数据的时间
2. SM 算法每次只加密 1000 条数据时间
3. 每次只更新 100 条数据的时间
ZhanXinjia
208 天前
@150530 就是用你原始的 id (唯一索引)和更新的结果(加密后的字符串)用 union all 拼接成一个临时表,然后根据原始表和临时表有一样的 id 来一一对应起来更新。
kestrelBright
208 天前
楼上说了加 rewriteBatchedStatements 参数
150530
208 天前
@ZhanXinjia 懂了懂了 UNION ALL 组虚拟表学到了
matepi
208 天前
insert 一张空表效率先看看?
如果空表效率可以,那么就可以 insert 完,再做联表 update
如果空表效率不可以,说明本身 batch 形式用法还存在问题
litchinn
208 天前
postgresql 有 rewriteBatchedStatements 参数吗
cnoder
208 天前
直接 update 吗,不应该是先双写嘛

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

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

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

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

© 2021 V2EX