我有一个包含用户数据的导入表,我需要标记具有重复字段值的行,因为它们不应导入。
CREATE TABLE `import` (
ID int(10) unsigned NOT NULL AUTO_INCREMENT,
method varchar(20) DEFAULT NULL,
f1 text,
f2 text,
PRIMARY KEY (ID)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
字段f1
可以包含重复值。选择它们的查询有效:
SELECT id, a.f1 FROM import a INNER JOIN
(
SELECT f1 FROM import
WHERE f1 IS NOT NULL AND f1 != ''
GROUP BY f1
HAVING COUNT(id) > 1
) b
ON a.f1 = b.f1
问题是进行更新的外部查询。这是整个shebang:
UPDATE import SET method = 'ERR_DUPLICATE' WHERE import.id IN
(
SELECT id FROM
(
SELECT id, a.f1 FROM import a INNER JOIN
(
SELECT f1 FROM import
WHERE f1 IS NOT NULL AND f1 != ''
GROUP BY f1
HAVING COUNT(id) > 1
) b
ON a.f1 = b.f1
) c
)
该构造来自MySQL: You can't specify target table 'tasks' for update in FROM clause - 这是我之前得到的错误。上述查询有效,但需要0.5秒。对于20,000行表,大约30个重复。我将不得不处理更大的导入表,所以这是一个显示阻止。
任何想法如何加快速度?
答案 0 :(得分:0)
试试这个修改过的版本:
CREATE TEMPORARY TABLE duplicate_ids
SELECT MAX(id) AS id FROM import
WHERE f1 IS NOT NULL AND f1 != ''
GROUP BY f1 ORDER BY NULL
HAVING COUNT(*) > 1;
UPDATE import SET method = 'ERR_DUPLICATE' WHERE import.id IN(
SELECT id FROM duplicate_ids
);
这将为您提供更大的ID记录作为副本。 ORDER BY NULL禁止由于分组而导致的隐式排序。 此外,由于条件和TEING列的GROUPing效率低下,您可以维护一个额外的列,该列将包含 f1 中文本的哈希码。
ALTER TABLE import ADD COLUMN f1_hash INT UNSIGNED NOT NULL;
ALTER TABLE import ADD KEY(f1_hash);
f1_hash填充了 CRC32(f1)(http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_crc32)返回的值。 CRC32可能会发生冲突,因此您必须最终检查 f1 列。
CREATE TEMPORARY TABLE duplicate_ids
SELECT i2.id FROM import i1 JOIN import i2
ON i2.id<>i1.id AND i1.f1_hash = i2.f2_hash
AND i1.f1_hash > 0 WHERE i1.f1 = i2.f1
然后像以前一样执行更新。 您当然不需要 f1 列上的INDEX,因此最好将其删除,因为它会增加不必要的开销。