我正在使用MySQL 5.6。我们假设我们有以下两个表格:
每个DataSet
都有大量的子DataEntry
条记录,其数量为10000或100000或更多。在一个事务中插入或删除其子DataSet.md5sum
个记录时,DataSet.version
和DataEntry
会更新。 DataSet.md5sum
针对其所有子项DataEntry.content
进行计算。
在这种情况下,从这两个表中获取一致数据的最有效方法是什么?
如果我发出以下两个不同的SELECT,我认为由于并发INSERT / UPDATE,我可能会得到不一致的数据:
SELECT md5sum, version FROM DataSet WHERE dataset_id = 1000
SELECT dataentry_id, content FROM DataEntry WHERE dataset_id = 1000
- 我认为此查询的结果可能与先前查询提取的md5sum不一致我认为我可以使用以下一个查询获得一致的数据:
SELECT e.dataentry_id, e.content, s.md5sum, s.version
FROM DataSet s
INNER JOIN DataEntry e ON (s.dataset_id = e.dataset_id)
WHERE s.dataset_id = 1000
但它产生的冗余数据集中填充了10000或100000个重复md5sum
s,所以我猜它效率不高(编辑:我担心的是高网络带宽和内存消耗)。
我认为使用悲观的读/写锁(SELECT ... LOCK IN SHARE MODE
/ FOR UPDATE
)将是另一种选择,但它似乎有点过分。还有其他更好的方法吗?
答案 0 :(得分:1)
连接将确保返回的数据不会受到两个单独选择之间发生的任何更新的影响,因为它们是作为单个查询执行的。
当你说md5sum和版本更新时,你的意思是子表上有一个触发器用于插入和更新吗?
当您加入表时,您将获得“重复的md5sum和版本”,因为您正在为DataEntry
表中的每个项目提取匹配记录。它非常好,不会成为效率问题。另一种方法是使用两个单独的选择,但是根据插入/更新的频率,没有事务,您可以获得可能略微关闭的数据的非常小的风险。
我会选择加入。您可以在mysql中运行查询解释计划,并查看查询的执行方式,并根据您的数据查看两种方法之间的差异,以及是否有任何索引等等。
将这些记录组运行到各种临时表中可能会更有益。在处理之前,您可以调用预处理器函数,该函数获取要处理的数据的“快照”,将副本放入临时表中。然后你可以只选择版本和md5sum,然后选择所有记录,作为两个不同的选择。由于这些被复制到一个单独的临时表中,您不必担心立即更新会破坏您的处理会话。您可以设置定时作业来执行此操作或将其作为按需调用。尽管如此,考虑到您正在使用的硬件/网络设置,这将是您研究最佳方法所需要的。以及您可以使用的任何作业调度软件。
答案 1 :(得分:0)
使用此模式:
START TRANSACTION;
SELECT ... FOR UPDATE; -- this locks the row
...
UPDATE ...
COMMIT;
(并在每个陈述后检查错误,包括COMMIT
。)
" 100000"不是"巨大",但" BIGINT"是。改为INT UNSIGNED
。
对于MD5,请确保您没有使用utf8:CHAR(32) CHARACTER SET ascii
。这适用于任何其他十六进制字符串。
或者,使用BINARY(16)
占空间的一半。然后在插入时使用UNHEX(md5...)
,在提取时使用HEX(...)
。
您关心带宽等。请描述您的客户端(PHP?Java?...)。请解释需要提取多少(100K行?)来重新创建MD5。
请注意,MySQL中有一个MD5功能。如果您的每个项目都有一个MD5,您可以使用MD5连接这些项目 - 并完全在服务器中完成;无需带宽。 (务必增加group_concat_max_len
)