使用两行从另一个表中删除重复项的最快方法

时间:2011-10-29 01:20:35

标签: mysql sql performance optimization join

表格

CREATE TABLE `pending` (
  `auto_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`auto_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=68176 ;

CREATE TABLE `errors` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `error` varchar(200) NOT NULL,
  `datechecked` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11553 ;

如果我想查看挂起的用户名和密码组合在错误中没有匹配的记录,我使用以下代码:

SELECT `pending`.username, `pending`.password FROM `pending` 
LEFT OUTER JOIN `errors` ON (
    `errors`.username = `pending`.username 
            AND 
    `errors`.password = `pending`.password
) WHERE (`errors`.username IS NULL)

详细说明用户名和密码组合的含义是给定这些表格,结果应为:

||||||pending table|||||||||
----------------------------
username    | password 
----------------------------
brian       | password1
brian       | password2
brian       | password3
brian       | password4



||||||errors table|||||||||
----------------------------
username    | password 
----------------------------
brian       | password2
brian       | password4


Result:

----------------------------
username    | password 
----------------------------
brian       | password1
brian       | password3

这样可行,但需要很长时间才能完成。我每天运行20次左右,随着错误表的增长,每个请求都会变得越来越长。我会说每个SQL语句最多5分钟,因为它们的入口大小为AUTO_INCREMENT值。

我有一种感觉,我可以使用用户名和密码制作某种索引并提高性能。虽然我不是100%肯定,这就是我要问的原因。

2 个答案:

答案 0 :(得分:1)

尝试使用NOT EXISTS代替LEFT JOIN。连接时MySQL相对较慢。

SELECT p.username, p.password
FROM   pending p
WHERE  NOT EXISTS (SELECT * FROM errors WHERE (username, password) = (p.username, p.password))

另外,请确保您有挂起(用户名,密码)和错误(用户名,密码)的索引。

CREATE INDEX username_password_idx ON pending (username, password);
CREATE INDEX username_password_idx ON errors (username, password);

答案 1 :(得分:0)

首先,确保pending {username, password}errors {username, password}都有复合索引。我不太熟悉MySQL查询优化器,但是大多数数据库(以及希望MySQL也是如此)应该能够使用这些索引进行有效的MERGE JOIN。

此外,MySQL查询优化器可能不够聪明,意识到WHERE (errors.username IS NULL)实际上并不需要全表扫描(即使有索引)。尝试这样的事情:

SELECT `pending`.username, `pending`.password
FROM `pending` 
WHERE
    NOT EXISTS (
        SELECT *
        FROM `errors`
        WHERE 
            `errors`.username = `pending`.username 
            AND `errors`.password = `pending`.password
    )