[英]Inefficient execution plan on MySQL query with multiple joins
我的MySQL有性能问题; 似乎我的请求的执行计划远非最佳,但我不知道为什么MySQL选择它,也不知道如何更改它。 我在最小环境中重现了该问题,这是查询:
SELECT member.id, member_cache.id, section.id, topic.id
FROM topic
INNER JOIN (section
INNER JOIN (member
LEFT JOIN (member_cache) ON member_cache.id = member.id
) ON member.id = section.last_member
) ON section.id = topic.section
WHERE topic.last_time IS NOT NULL
ORDER BY topic.last_time DESC
LIMIT 0, 1
这是此查询中使用的表:
CREATE TABLE `member` (`id` int(10) unsigned NOT NULL)
ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `member_cache` (`id` int(10) unsigned NOT NULL)
ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `section` (`id` int(10) unsigned NOT NULL, `last_member` int(10) unsigned NOT NULL DEFAULT '0')
ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `topic` (`id` int(10) unsigned NOT NULL, `section` int(10) unsigned NOT NULL, `last_time` int(10) unsigned NOT NULL)
ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `member` ADD PRIMARY KEY (`id`);
ALTER TABLE `member_cache` ADD PRIMARY KEY (`id`);
ALTER TABLE `section`ADD PRIMARY KEY (`id`);
ALTER TABLE `topic` ADD PRIMARY KEY (`id`), ADD KEY `section__last_time` (`section`,`last_time`), ADD KEY `last_time` (`last_time`);
现在这是执行计划,通过“ EXPLAIN <上面的查询>”获得:
+----+-------------+--------------+--------+------------------------------+--------------------+---------+-------------------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+--------+------------------------------+--------------------+---------+-------------------------------+------+---------------------------------+
| 1 | SIMPLE | section | ALL | PRIMARY | NULL | NULL | NULL | 2188 | Using temporary; Using filesort |
| 1 | SIMPLE | member | eq_ref | PRIMARY | PRIMARY | 4 | temporary.section.last_member | 1 | Using index |
| 1 | SIMPLE | member_cache | eq_ref | PRIMARY | PRIMARY | 4 | temporary.section.last_member | 1 | Using index |
| 1 | SIMPLE | topic | ref | section__last_time,last_time | section__last_time | 4 | temporary.section.id | 106 | Using index condition |
+----+-------------+--------------+--------+------------------------------+--------------------+---------+-------------------------------+------+---------------------------------+
如您所见,它是通过扫描整个“ section”表开始的,使用一个临时表并导致了糟糕的性能。 我真的不明白为什么会发生这种情况,因为“ topic.last_time”(用于WHERE子句)和“ section.id”(用于第一个INNER JOIN)都存在一个索引。 我也做了一些测试,结果非常不稳定:
这是应用上述三个更改中的任何一个之后的执行计划:
+----+-------------+--------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
| 1 | SIMPLE | topic | index | last_time | last_time | 4 | NULL | 1 | Using where |
| 1 | SIMPLE | section | eq_ref | PRIMARY | PRIMARY | 4 | temporary.topic.section | 1 | NULL |
| 1 | SIMPLE | member | eq_ref | PRIMARY | PRIMARY | 4 | temporary.section.last_member | 1 | Using index |
| 1 | SIMPLE | member_cache | eq_ref | PRIMARY | PRIMARY | 4 | temporary.section.last_member | 1 | Using index |
+----+-------------+--------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
我还尝试“优化表”所有表或切换到InnoDB引擎,但这些表均未更改。 问题在MySQL 5.5.35和5.6.15版本上已被复制; 我还在此处上传了测试环境的快照,可以轻松重现上面的查询。
你知道什么可以解释这个执行计划吗?
考虑在section.last_member,section.id上添加索引。
ALTER TABLE section ADD KEY(last_member, id);
如果它们是innodb,则可以省略ID,因为它已经是PK。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.