Bug #65274 | MySQL misplanning query with index_merge | ||
---|---|---|---|
Submitted: | 10 May 2012 5:53 | Modified: | 3 Aug 2012 15:44 |
Reporter: | Max Barry | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | 5.1.*, 5.5.*, 5.6.6 | OS: | Linux (Ubuntu Server 12.04) |
Assigned to: | CPU Architecture: | Any | |
Tags: | index_merge |
[10 May 2012 5:53]
Max Barry
[10 May 2012 14:41]
Valeriy Kravchuk
It would be nice to know the exact output of SHOW CREATE TABLE and SHOW TABLE STATUS for the table used, and the output of: SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126 AND forum_id = 19; SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126; SELECT count(*) FROM phpbb_posts WHERE forum_id = 19; for values where supposedly wrong execution path is used. This can be a duplicate of Bug #32254, for example.
[10 May 2012 23:52]
Max Barry
On 10 May 14:41 Valeriy Kravchuk wrote: > > It would be nice to know the exact output of SHOW CREATE TABLE and > SHOW TABLE STATUS for the table used, and the output of: > > SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126 AND forum_id = 19; > SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126; > SELECT count(*) FROM phpbb_posts WHERE forum_id = 19; > > for values where supposedly wrong execution path is used. Thanks for the response! Sorry for not including that table info earlier. mysql> SHOW CREATE TABLE phpbb_posts \G *************************** 1. row *************************** Table: phpbb_posts Create Table: CREATE TABLE `phpbb_posts` ( `post_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `topic_id` mediumint(8) unsigned NOT NULL DEFAULT '0', `forum_id` mediumint(8) unsigned NOT NULL DEFAULT '0', `poster_id` mediumint(8) unsigned NOT NULL DEFAULT '0', `icon_id` mediumint(8) unsigned NOT NULL DEFAULT '0', `poster_ip` varchar(40) COLLATE utf8_bin NOT NULL DEFAULT '', `post_time` int(11) unsigned NOT NULL DEFAULT '0', `post_approved` tinyint(1) unsigned NOT NULL DEFAULT '1', `post_reported` tinyint(1) unsigned NOT NULL DEFAULT '0', `enable_bbcode` tinyint(1) unsigned NOT NULL DEFAULT '1', `enable_smilies` tinyint(1) unsigned NOT NULL DEFAULT '1', `enable_magic_url` tinyint(1) unsigned NOT NULL DEFAULT '1', `enable_sig` tinyint(1) unsigned NOT NULL DEFAULT '1', `post_username` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '', `post_subject` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `post_text` mediumtext COLLATE utf8_bin NOT NULL, `post_checksum` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '', `post_attachment` tinyint(1) unsigned NOT NULL DEFAULT '0', `bbcode_bitfield` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '', `bbcode_uid` varchar(8) COLLATE utf8_bin NOT NULL DEFAULT '', `post_postcount` tinyint(1) unsigned NOT NULL DEFAULT '1', `post_edit_time` int(11) unsigned NOT NULL DEFAULT '0', `post_edit_reason` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '', `post_edit_user` mediumint(8) unsigned NOT NULL DEFAULT '0', `post_edit_count` smallint(4) unsigned NOT NULL DEFAULT '0', `post_edit_locked` tinyint(1) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`post_id`), KEY `topic_id` (`topic_id`), KEY `poster_ip` (`poster_ip`), KEY `poster_id` (`poster_id`), KEY `post_approved` (`post_approved`), KEY `tid_post_time` (`topic_id`,`post_time`), KEY `post_username` (`post_username`), KEY `tid_fid` (`topic_id`,`forum_id`), KEY `fid_tid_post_time` (`forum_id`,`topic_id`,`post_time`), KEY `forum_id` (`forum_id`) ) ENGINE=MyISAM AUTO_INCREMENT=9189247 DEFAULT CHARSET=utf8 COLLATE=utf8_bin 1 row in set (0.00 sec) mysql> SHOW TABLE STATUS WHERE name = 'phpbb_posts' \G *************************** 1. row *************************** Name: phpbb_posts Engine: MyISAM Version: 10 Row_format: Dynamic Rows: 7461329 Avg_row_length: 853 Data_length: 6371126872 Max_data_length: 281474976710655 Index_length: 709460992 Data_free: 0 Auto_increment: 9189247 Create_time: 2012-05-06 00:01:10 Update_time: 2012-05-06 00:02:53 Check_time: 2012-05-06 00:09:06 Collation: utf8_bin Checksum: NULL Create_options: Comment: 1 row in set (0.00 sec) mysql> SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126 AND forum_id = 19; +----------+ | count(*) | +----------+ | 46651 | +----------+ 1 row in set (2 min 8.98 sec) mysql> SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126; +----------+ | count(*) | +----------+ | 46651 | +----------+ 1 row in set (0.02 sec) mysql> SELECT count(*) FROM phpbb_posts WHERE forum_id = 19; +----------+ | count(*) | +----------+ | 264808 | +----------+ 1 row in set (0.34 sec) And just in case it's useful, EXPLAIN statements for the above: mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126 AND forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: index_merge possible_keys: topic_id,tid_post_time,tid_fid,fid_tid_post_time,forum_id key: topic_id,forum_id key_len: 3,3 ref: NULL rows: 1592 Extra: Using intersect(topic_id,forum_id); Using where; Using index 1 row in set (0.00 sec) mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE topic_id = 110126 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: topic_id,tid_post_time,tid_fid key: topic_id key_len: 3 ref: const rows: 45746 Extra: Using index 1 row in set (0.00 sec) mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.00 sec)
[11 May 2012 17:06]
Sveta Smirnova
Thank you for the feedback. For me output of SELECT COUNT(*) confirms this is duplicate of bug #32254. Only thing which confuses me is: mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.00 sec) Strange why forum_id was not used here. Please try to run OPTIMIZE TABLE phpbb_posts and check if plan is changes. Please also try queries with your table in version 5.6 to be sure if this is duplicate of bug #32254 and not new problem.
[16 May 2012 4:21]
Max Barry
On 11 May 17:06 Sveta Smirnova wrote: > Please try to run OPTIMIZE TABLE phpbb_posts and check if plan is changes. It didn't change: mysql> use forum; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.14 sec) mysql> OPTIMIZE TABLE phpbb_posts; +-------------------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +-------------------+----------+----------+----------+ | forum.phpbb_posts | optimize | status | OK | +-------------------+----------+----------+----------+ 1 row in set (7.15 sec) mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.00 sec) > Please also try queries with your table in version 5.6 I'll try that next.
[16 May 2012 5:22]
Max Barry
On 11 May 17:06 Sveta Smirnova wrote: > Please also try queries with your table in version 5.6 That made no difference either: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.5-m8-log MySQL Community Server (GPL) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use forum; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.00 sec) mysql> OPTIMIZE TABLE phpbb_posts; +-------------------+----------+----------+-----------------------------+ | Table | Op | Msg_type | Msg_text | +-------------------+----------+----------+-----------------------------+ | forum.phpbb_posts | optimize | status | Table is already up to date | +-------------------+----------+----------+-----------------------------+ 1 row in set (0.00 sec) mysql> ANALYZE TABLE phpbb_posts; +-------------------+---------+----------+-----------------------------+ | Table | Op | Msg_type | Msg_text | +-------------------+---------+----------+-----------------------------+ | forum.phpbb_posts | analyze | status | Table is already up to date | +-------------------+---------+----------+-----------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT count(*) FROM phpbb_posts WHERE forum_id = 19 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: ref possible_keys: fid_tid_post_time,forum_id key: fid_tid_post_time key_len: 3 ref: const rows: 161103 Extra: Using index 1 row in set (0.00 sec) mysql>
[16 May 2012 5:24]
Max Barry
Er, I forgot the original query in my last comment. Here it is still using index_merge on 5.6.5: mysql> EXPLAIN SELECT post_id, topic_id, forum_id FROM phpbb_posts WHERE topic_id = 110126 AND forum_id = 19 ORDER BY post_time ASC LIMIT 1 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: phpbb_posts type: index_merge possible_keys: topic_id,tid_post_time,tid_fid,fid_tid_post_time,forum_id key: topic_id,forum_id key_len: 3,3 ref: NULL rows: 1592 Extra: Using intersect(topic_id,forum_id); Using where; Using filesort 1 row in set (0.00 sec)
[25 May 2012 22:44]
Sveta Smirnova
Thank you for the feedback. Verified as described. Simplified test case will be uploaded to internal server. Queries for simplified test case: mysql> SELECT post_id, topic_id, forum_id FROM t1 WHERE topic_id = 35 AND forum_id = 19 ORDER BY post_time ASC LIMIT 1; +---------+----------+----------+ | post_id | topic_id | forum_id | +---------+----------+----------+ | 11394 | 35 | 19 | +---------+----------+----------+ 1 row in set (0.56 sec) mysql> SELECT post_id, topic_id, forum_id FROM t1 ignore index(forum_id) WHERE topic_id = 35 AND forum_id = 19 ORDER BY post_time ASC LIMIT 1; +---------+----------+----------+ | post_id | topic_id | forum_id | +---------+----------+----------+ | 11394 | 35 | 19 | +---------+----------+----------+ 1 row in set (0.28 sec) mysql> explain SELECT post_id, topic_id, forum_id FROM t1 WHERE topic_id = 35 AND forum_id = 19 ORDER BY post_time ASC LIMIT 1; +----+-------------+-------+-------------+---------------------------+-------------------+---------+------+------+-----------------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------------+---------------------------+-------------------+---------+------+------+-----------------------------------------------------------------+ | 1 | SIMPLE | t1 | index_merge | topic_id,tid_fid,forum_id | forum_id,topic_id | 3,3 | NULL | 2200 | Using intersect(forum_id,topic_id); Using where; Using filesort | +----+-------------+-------+-------------+---------------------------+-------------------+---------+------+------+-----------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> explain SELECT post_id, topic_id, forum_id FROM t1 ignore index(forum_id) WHERE topic_id = 35 AND forum_id = 19 ORDER BY post_time ASC LIMIT 1; +----+-------------+-------+------+------------------+---------+---------+-------------+-------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+------------------+---------+---------+-------------+-------+-----------------------------+ | 1 | SIMPLE | t1 | ref | topic_id,tid_fid | tid_fid | 6 | const,const | 84294 | Using where; Using filesort | +----+-------------+-------+------+------------------+---------+---------+-------------+-------+-----------------------------+ 1 row in set (0.00 sec) And here is the explanation: index merge allows to examine only 2200 rows instead of 84294 with composite index (x38 times), although it badly affects performance. Workarounds: 1. Use FORCE INDEX 2. SET optimizer_switch='index_merge=off'
[30 May 2012 17:02]
Sveta Smirnova
Bug #65359 was marked as duplicate of this one.
[3 Aug 2012 15:44]
Paul DuBois
Noted in 5.6.7, 5.7.0 changelogs. For some queries, the optimizer used index_merge access method when this was more work than ref access.