我试图在一个“交易”中将许多(从几十到几百个)类似的记录插入一个表中。记录仅因主键和另外一个字段而异。该表是一个MEMORY表,插入的记录经常更新并经常删除,但有些可以在表中保留一天。表结构:
id BIGINT
sid CHAR
pid INT
mask INT
param1 INT
param2 INT
... INT
paramN INT
PRIMARY (id, sid),
KEY [BTREE] (sid), (param1), (param2), (...), (paramN)
现在插入是通过准备好的声明发生的:
INSERT INTO object_subscriptions (id, sid, pid, mask, ...)
VALUES (:id, :sid, :pid, :mask, ...)
ON DUPLICATE KEY UPDATE mask = mask | VALUES(mask)
样本记录:
13194140000467 | 'fBF8OfQlAjSS8uXsAAzx' | 7 | 22 | 3 | 0 | 188 | 5123 | 1
18392199238192 | 'fBF8OfQlAjSS8uXsAAzx' | 7 | 22 | 3 | 0 | 188 | 5123 | 1
26342478965721 | 'fBF8OfQlAjSS8uXsAAzx' | 7 | 22 | 3 | 0 | 188 | 5123 | 1
64322445645318 | 'fBF8OfQlAjSS8uXsAAzx' | 7 | 22 | 3 | 0 | 188 | 5123 | 1
13194140000467 | 'n2pFykYGNnsp-JfCAeJO' | 5 | 97 | 1293 | 0 | 188 | 5123 | 0
18392199238192 | 'n2pFykYGNnsp-JfCAeJO' | 5 | 97 | 1293 | 0 | 188 | 5123 | 0
26342478965721 | 'n2pFykYGNnsp-JfCAeJO' | 5 | 97 | 1293 | 0 | 188 | 5123 | 0
64322445645318 | 'n2pFykYGNnsp-JfCAeJO' | 5 | 97 | 1293 | 0 | 188 | 5123 | 0
这在每批数十个记录中效果很好。每批数百个,它急剧减速。一个明显的优化,可以使性能提高一倍或三倍,就是在一个语句中有多个VALUE集,但这仍然会带来发送N params
以及sid
和pid
的开销。每条记录,即使只有一个批次中只有id
和mask
不同。
我在考虑在准备好的语句中包含这些“固定”值,但这些“参数”是从用户输入生成的,不受信任。由于数据更改的频率和需要执行的索引查找次数,我对MySQL和MEMORY感到困惑。否则我会规范化数据或将所有内容移动到键值存储。
答案 0 :(得分:1)
这是我能想到避免重复共同元素的唯一方法。不幸的是,它可能是如此冗长,以至于它并不比你要替换的更好。
INSERT INTO object_subscriptions (id, sid, pid, mask, ...)
SELECT t1.id, t2.sid, t2.pid, t1.mask, ...
FROM (SELECT :id1 id, :mask1 mask
UNION
SELECT :id2, :mask2
UNION
SELECT :id3, :mask3
...
) t1
JOIN (SELECT :sid sid, :pid pid, ...) t2
这只是一批。要在单个查询中执行多个批处理,您可以将UNION
添加到顶级SELECT
。
INSERT INTO object_subscriptions (id, sid, pid, mask, ...)
SELECT t1.id, t2.sid, t2.pid, t1.mask, ...
FROM (SELECT :batch1_id1 id, :batch1_mask1 mask
UNION
SELECT :batch1_id2, :batch1_mask2
UNION
SELECT :batch1_id3, :batch1_mask3
...
) t1
JOIN (SELECT :batch1_sid sid, :batch1_pid pid, ...) t2
UNION
SELECT t1.id, t2.sid, t2.pid, t1.mask, ...
FROM (SELECT :batch2_id1 id, :batch2_mask1 mask
UNION
SELECT :batch2_id2, :batch2_mask2
UNION
SELECT :batch2_id3, :batch2_mask3
...
) t1
JOIN (SELECT :batch2_sid sid, :batch2_pid pid, ...) t2
UNION
...
答案 1 :(得分:0)
使用多行插入:
INSERT INTO object_subscriptions (id, sid, pid, mask, ...)
VALUES (:id[0], :sid[0], :pid[0], :mask[0], ...),
(:id[1], :sid[1], :pid[`], :mask[1], ...), ...
ON DUPLICATE KEY UPDATE mask = mask | VALUES(mask)
这将减少客户端 - 服务器的来回流量,并允许MySQL使用一些内部批量加载优化。