我想比较具有相同列的两个巨大的表来查找具有不同值的记录。 (两个表中的许多行都是相同的)
需要花费大量时间,性能非常差,查询现在看起来像这样:
SELECT *
FROM table1 a
INNER JOIN table2 b
ON a.value!=b.value
OR a.value!=b.value
OR a.value!=b.value
OR a.value!=b.value
OR a.value!=b.value
OR a.value!=b.value
OR a.value!=b.value OR...
WHERE a.id=1
AND b.id=2
AND a.specialvalue=b.specialvalue;
想法是创建我需要比较的所有值的校验和,并仅比较行的校验和。我的问题是:这是一个好方法吗?性能会有提升吗?是否有可能在合理的时间内将两行与100k记录进行比较?
答案 0 :(得分:1)
如果你需要检查每个100K的100K行,那就是大约50 亿比较。这将花费比你想象的更长的时间。但是你可以这样做:
CREATE Cksums (
md5 CHAR(32) CHARACTER SET ascii,
id ..., -- PK of the row
INDEX(md5)
);
INSERT INTO Cksums (md5, id)
SELECT
MD5(CONCAT_WS("\t", col2, col3, ...),
id
FROM your_table;
然后查找dup行:
SELECT md5,
GROUP_CONCAT(id) AS dup_ids
FROM Cksums
GROUP BY md5
HAVING COUNT(*) > 1;
DROP TABLE Cksums; -- cleanup
这将通过两次100K表扫描有效地进行500亿次比较(一次用于构建Cksums,一次用于检查)。
注意事项:
NULLs
。BLOBs
应通过HEX(the_blob)
提取,以避免CONCAT_WS
中的各种问题。GROUP_CONCAT
将截断列表。答案 1 :(得分:1)
检查两个表是否相同的快速方法是使用MySQL的CHECKSUM TABLE
命令。如果两个表给出相同的校验和,那么两个表中的所有数据完全同步,你就完成了。
如果校验和不同,那么您可以查看更多细节以找出哪些行不同。
Percona Toolkit包含一个工具pt-table-sync
,可以更有效地执行两个表之间的数据比较。你需要安装Perl,以及Perl模块DBI和DBD :: mysql。
例如,我想在我的测试数据库中比较两个相同的表,这些表称为死锁和死锁2。首先,我只是想看看有什么不同之处:
$ pt-table-sync --print h=localhost,D=test,t=deadlocks t=deadlocks2
输出显示了一系列INSERT
/ UPDATE
/ DELETE
语句,这些语句是使deadlocks2表与deadlocks表具有相同数据所必需的。
如果您已准备好同步它们,请将print更改为执行,它将执行SQL更改:
$ pt-table-sync --execute h=localhost,D=test,t=deadlocks t=deadlocks2
之后,每个表的CHECKSUM TABLE
应匹配。
另一个选项是来自MySQL Utilities的mysqldbcompare。我没有这个工具的经验,但似乎它将比较两个完整数据库的所有表中的数据。我不知道是否可以选择比较具有不同名称但结构相似的两个表。
Percona Toolkit和MySQL Utilities都是免费软件。
答案 2 :(得分:1)
这里有一些很棒的答案,包括我最喜欢的pt-table-checksum
。
如果您只需要执行此操作并希望快速找到差异,请考虑使用mysqldump
或SELECT ... INTO OUTFILE
将表转储为两个单独的文件,然后使用旧的{{在命令行上执行命令。