复杂的mysql更新查询很慢

时间:2011-06-23 22:40:22

标签: mysql

我有一个包含用户数据的导入表,我需要标记具有重复字段值的行,因为它们不应导入。

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个重复。我将不得不处理更大的导入表,所以这是一个显示阻止。

任何想法如何加快速度?

1 个答案:

答案 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,因此最好将其删除,因为它会增加不必要的开销。