表格
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%肯定,这就是我要问的原因。
答案 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
)