I have a performance issue with MySQL ; it seems execution plan for my request is far from optimal, but I don't know why MySQL chooses it nor how I could change it. I reproduced the issue within a minimal environment, and here is the query:
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
And here are the tables used in this query:
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`);
Now here is execution plan, obtained with "EXPLAIN <the query above>":
+----+-------------+--------------+--------+------------------------------+--------------------+---------+-------------------------------+------+---------------------------------+
| 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 |
+----+-------------+--------------+--------+------------------------------+--------------------+---------+-------------------------------+------+---------------------------------+
As you can see it starts by scanning the entire "section" table, using a temporary table and causing terrible performances. I don't really understand why this happens, since an index exists on both "topic.last_time" (used in WHERE clause) and "section.id" (used in first INNER JOIN). I also did several tests and this result is pretty unstable:
Here is the execution plan I have after applying any of the three changes above:
+----+-------------+--------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
| 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 |
+----+-------------+--------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
I also tried to "OPTIMIZE TABLE" all tables or switch to InnoDB engine but neither of those changed anything. Issue was reproduced on MySQL versions 5.5.35 and 5.6.15 ; I also uploaded a snapshot of the test environment here , where the queries above can be easily reproduced.
Do you know what could explain this execution plan?
Consider adding an index on section.last_member, section.id.
ALTER TABLE section ADD KEY(last_member, id);
If they are innodb you can omit ID since it is already a PK.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.