我有mysql表,它有结构
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| content | longtext | NO | | NULL | |
| valid | tinyint(1) | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------+------------------+------+-----+---------+----------------+
我需要删除content
列的重复条目,如果不是longtext,一切都会很简单,主要问题是该列中的条目长度从1个字符到12,000个以上字符不等,我有超过4,000,000个条目,像select id from table where content like "%stackoverflow%";
之类的简单查询需要15秒来执行,删除重复条目的最佳方法是什么,而不是等待2天执行查询?
答案 0 :(得分:1)
md5是你的朋友。使用hashvalues
和id
的列创建单独的hash
表(以避免与生产中的此表锁定/争用)。此表的主键实际上应该是hash
列,而不是id
。
创建新的空表后,使用MySql的md5()
函数从原始数据中填充新表格,原始id
和md5(content)
字段值。如果有必要,您甚至可以批量填充表格,如果需要花费太长时间或减慢太多而无法立即完成所有操作。
当新表格完全填充数据时,您可以JOIN
将其自身填充为:
SELECT h1.*
FROM hashvalues h1
INNER JOIN hashvalues h2 on h1.hash = h2.hash and h1.id <> h2.id
这比直接比较content
要快 MUCH ,因为数据库只需要比较预先计算的哈希值。我期待几乎立刻跑。它会告诉您哪些记录潜在重复。仍然存在散列冲突的可能性,因此您还需要将其与原始数据进行比较以确定,或者在新表中包含originalcontent
列,您可以将其与上面的查询一起使用。完成后,您将知道要删除哪些记录。
如果您可以在原始表中添加列,以便在每次更改时md5()
字段的content
哈希值保持最新,则此系统可能会更好。如果您拥有合适的存储引擎,Generated Column将适用于此。否则,您可以使用触发器。此列允许您根据需要重新运行重复项检查,而无需使用单独的表进行所有额外工作。
最后,还有Sha()
,Sha1()
和Sha2()
函数可能更具抗冲突性。但是,md5()
将更快,并且额外的碰撞阻力不足以避免也需要比较原始数据。这也不是碰撞潜力很重要的安全情况,因此md5()
是更好的选择。毕竟,这些都不是密码。