Go 语言 MySQL Update 200 万条数据的正确姿势是什么?

2017-07-20 16:53:38 +08:00
 billion

根据主键来更新每一条数据。

stmt, err := db.Prepare("update xxx set age=? where primaryid = ?")
panic(err)
_, err2 := stmt.Exec(age, id)

由于主键是唯一的,所以需要一条一条的更新。这种情况下,开了 2000 个 goroute 速度还是非常慢。请问有什么好办法吗?

6009 次点击
所在节点    Go 编程语言
46 条回复
billion
2017-07-20 17:43:44 +08:00
@honeycomb 这正是我想要的东西,非常感谢你的回答。
realfreesky
2017-07-20 17:44:28 +08:00
@sunchen 有更具体的操作方法不
DCjanus
2017-07-20 18:42:40 +08:00
生成 csv 然后用 MySQL 的 load data infile 功能
使用这个是单个事务且所有数据导入后才重建索引,比其他方法快很多。
注意处理唯一键冲突,选择 ignore 或者 replace
0x8C
2017-07-20 18:46:16 +08:00
tide
jarlyyn
2017-07-20 18:50:22 +08:00
@billion

觉得 go 拼接 sql 语句麻烦是因为你不知道 sqlx 吧?
fuxkcsdn
2017-07-20 19:04:14 +08:00
用 set case when 进行批量更新
akrf
2017-07-20 19:28:35 +08:00
上面那个关于 innoDB 的言论说反了
orvice
2017-07-20 19:53:55 +08:00
拼接语句,一次生成 1000 条语句在执行
janxin
2017-07-20 20:35:44 +08:00
用个 Golang ORM,告别手拼比如 jinzhu 的 gorm
mchl
2017-07-20 21:04:35 +08:00
transaction
cxbig
2017-07-20 21:04:47 +08:00
@utopia5719 我说的锁表概念是错的
关于 insert ... key update 快是看情况的,处理单条数据 update 当然快,但是 insert ... key update 可以放多条记录在一个 SQL 里的。根据 LZ 的情况,一次处理 1 千条数据,应该是比处理一千条 update 快。除非 age 是同一个值。
sagaxu
2017-07-20 21:13:43 +08:00
@cxbig UPDATE a
SET fruit = (CASE id WHEN 1 THEN 'apple'
WHEN 2 THEN 'orange'
WHEN 3 THEN 'peach'
END)
WHERE id IN(1,2 ,3);

很多 orm 支持这种批量 update,不需要用 insert
cxbig
2017-07-20 21:21:04 +08:00
@sagaxu 这种我没试过,回头验证一下。
cxh116
2017-07-20 21:29:00 +08:00
@utopia5719 因为一行 insert on duplicate 可以一次更新一千条记录,每条记录更新为不同值。

而用 update set 要更新不同值,只能写 1000 条语句。
mengskysama
2017-07-20 21:39:05 +08:00
关了 auto commit 一个 query 还是一个 round trip,还是 batch 快,比如 32l 的
mingyun
2017-07-20 23:53:25 +08:00
@sagaxu 上百个 id 这个 sql 得有多长
msg7086
2017-07-21 04:38:23 +08:00
@mingyun 越长越快啊,没毛病。大量短语句才会变慢。

这里 INSERT ON DUPLICATE 其实比较好,因为只更新一两个值,SQL 语句并不会很臃肿。
jiazhoulvke
2017-07-21 06:52:35 +08:00
这和用什么语言没太大关系,主要是这种提交方式的问题,用事务会快很多。
fuxkcsdn
2017-07-21 08:27:57 +08:00
@cxbig 我 26 楼就说了,这方法批量更新很快

我昨天特地在我 16 年的 MacBook Air 128G SSD 上测试,200 万条简单数据的情况下(单条 SQL 更新 2000 条数据),60 秒左右更新完(用 PHP 7.0 PDO mysqli 驱动)
预期测试
age 有(无)索引,有(无)事务
单条更新(不打算测试,肯定慢得一逼)
set case when 批量更新(已测无索引,无事务)
insert on dup
fuxkcsdn
2017-07-21 08:36:58 +08:00
对了,按理说,楼主举的这例子,先根据 new_age (在程序或 sql 中)进行 group,然后用
update set age=new_age where id in (1, 2...)
更新应该是最快的

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

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

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

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

© 2021 V2EX