我有两个查询,第一个(内连接)超快,第二个(左连接)超慢。如何使第二个查询更快?
EXPLAIN SELECT saved.email FROM saved INNER JOIN finished ON finished.email = saved.email;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE finished index NULL email 258 NULL 32168 Using index
1 SIMPLE saved ref email email 383 func 1 Using where; Using index
EXPLAIN SELECT saved.email FROM saved LEFT JOIN finished ON finished.email = saved.email;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE saved index NULL email 383 NULL 40971 Using index
1 SIMPLE finishedindex NULL email 258 NULL 32168 Using index
编辑:我在下面为两个表格添加了表格信息。
CREATE TABLE `saved` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`slug` varchar(255) DEFAULT NULL,
`email` varchar(127) NOT NULL,
[omitted fields include varchar, text, longtext, int],
PRIMARY KEY (`id`),
KEY `slug` (`slug`),
KEY `email` (`email`)
) ENGINE=MyISAM AUTO_INCREMENT=56329 DEFAULT CHARSET=utf8;
CREATE TABLE `finished` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`slug` varchar(255) DEFAULT NULL,
`submitted` int(11) DEFAULT NULL,
`status` int(1) DEFAULT '0',
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
[omitted fields include varchar, text, longtext, int],
PRIMARY KEY (`id`),
KEY `assigned_user_id` (`assigned_user_id`),
KEY `event_id` (`event_id`),
KEY `slug` (`slug`),
KEY `email` (`email`),
KEY `city_id` (`city_id`),
KEY `status` (`status`),
KEY `recommend` (`recommend`),
KEY `pending_user_id` (`pending_user_id`),
KEY `submitted` (`submitted`)
) ENGINE=MyISAM AUTO_INCREMENT=33063 DEFAULT CHARSET=latin1;
最佳答案
对于INNER JOIN,MySQL一般会从行数最少的表开始。在这种情况下,它从表 finished
开始,并使用 saved.email
上的索引在 saved
中查找相应的记录。
对于 LEFT JOIN,(不包括一些优化)MySQL 通常按顺序连接记录(从最左边的表开始)。在这种情况下,MySQL 从表 saved
开始,然后尝试在 finished
中找到每个对应的记录。由于 finished.email
上没有可用索引,因此它必须对每次查找进行全面扫描。
编辑
现在您发布了您的模式,我可以看到 MySQL 在从 utf8
到 latin1
时忽略了索引 (finished.email
) > 字符集。您还没有发布每一列的字符集和排序规则,所以我将使用表的默认字符集。排序规则必须兼容,MySQL 才能使用索引。
MySQL 可以强制(升级)一个 latin1
排序规则,这是非常有限的,直到一个 utf8
排序规则,例如 unicode_ci
(所以第一个查询可以通过将 latin1
排序规则升级为 utf8
来使用 saved.email
上的索引,但反之则不然(第二个查询可以不要在 finished.email
上使用索引,因为它无法将 utf8
排序规则降级为 latin1
)。
解决方案是将两个电子邮件列更改为兼容的排序规则,也许最简单的方法是使它们具有相同的字符集和排序规则。
关于mysql - 为什么 LEFT JOIN 比 INNER JOIN 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27787269/