Bug #45969 the query otimizer choose the wrong index
| Submitted: | 6 Jul 2009 12:23 | Modified: | 8 Oct 2012 15:31 |
|---|---|---|---|
| Reporter: | Manfred Wiedemeier | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
| Version: | 5.1.35, 5.1.38-bzr | OS: | Windows (XP, Vista) |
| Assigned to: | CPU Architecture: | Any | |
| Tags: | regression | ||
[6 Jul 2009 12:29]
Valeriy Kravchuk
OK, different index is used (this is related to partial fix for bug #28404 we have in 5.1.x). But why do you think this is a bug? Do you have seriously slower execution? Please, send also the results of: SELECT recid_r02, count(*) FROM r03 GROUP BY recid_r02 ORDER BY 2 DESC LIMIT 10; I want to know how many rows in the table may have particular recid_r02 value.
[20 Jul 2009 11:03]
Manfred Wiedemeier
I've got 85.000 records in R02 and 80.000 in R03.
The execution time has changed from < 1 sec. to > 280 sec.
SELECT recid_r02, count(*) FROM r03
GROUP BY recid_r02
ORDER BY 2 DESC LIMIT 10;
recid_r02 count(*)
27256 3361
23569 3222
19452 3155
15370 3065
12801 2407
12796 1996
12793 1859
0 513
12802 301
29625 282
[22 Jul 2009 9:28]
Sveta Smirnova
Thank you for the feedback. I can not repeat described behavior: in case of MySQL-5.1 I get recid_r02 too. Please run OPTIMIZE TABLE on 5.1 server and inform us if it changed results.
[27 Jul 2009 8:36]
Manfred Wiedemeier
I optimize the tables, same result. The optimizer choose index `key6` and not `recid_r02`. If you like i can send you my database.
[27 Jul 2009 9:25]
Sveta Smirnova
Thank you for the feedback. > If you like i can send you my database. Yes, this would be good.
[27 Jul 2009 11:26]
Manfred Wiedemeier
I have uploaded "bug-data-45969.zip" to your ftp-server.
[30 Jul 2009 13:43]
Valeriy Kravchuk
Verified just as described using your tables uploaded with latest 5.1.38-bzr on Linux:
openxs@suse:/home2/openxs/dbs/5.1> bin/mysql -uroot reg00003
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.1.38-debug Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show tables;
+--------------------+
| Tables_in_reg00003 |
+--------------------+
| r02 |
| r03 |
+--------------------+
2 rows in set (0.01 sec)
mysql> explain SELECT r02.*,
-> (SELECT r03.r_datum
-> FROM r03
-> WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9)))
-> ORDER BY r03.r_datum DESC
-> LIMIT 1
-> ) AS last_order
->
-> FROM r02
-> WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE)
-> ORDER BY r02.auftrag DESC
-> LIMIT 50
->
-> ;
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
| 1 | PRIMARY | r02 | range | key | key | 4 | NULL | 27056 | Using where |
| 2 | DEPENDENT SUBQUERY | r03 | index | recid_r02 | key6 | 3 | NULL | 1 | Using where |
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
2 rows in set (0.02 sec)
As you correctly noted index recid_r02 can be used:
openxs@suse:/home2/openxs/dbs/5.1> bin/mysql -uroot reg00003
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.1.38-debug Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show tables;
+--------------------+
| Tables_in_reg00003 |
+--------------------+
| r02 |
| r03 |
+--------------------+
2 rows in set (0.01 sec)
mysql> explain SELECT r02.*,
-> (SELECT r03.r_datum
-> FROM r03
-> WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9)))
-> ORDER BY r03.r_datum DESC
-> LIMIT 1
-> ) AS last_order
->
-> FROM r02
-> WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE)
-> ORDER BY r02.auftrag DESC
-> LIMIT 50
->
-> ;
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
| 1 | PRIMARY | r02 | range | key | key | 4 | NULL | 27056 | Using where |
| 2 | DEPENDENT SUBQUERY | r03 | index | recid_r02 | key6 | 3 | NULL | 1 | Using where |
+----+--------------------+-------+-------+---------------+------+---------+------+-------+-------------+
2 rows in set (0.02 sec)
mysql> explain SELECT r02.*, (SELECT r03.r_datum FROM r03 WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9))) ORDER BY r03.recid_r02, r03.r_datum DESC LIMIT 1 ) AS last_order FROM r02 WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE) ORDER BY r02.auftrag DESC LIMIT 50;
+----+--------------------+-------+-------+---------------+-----------+---------+--------------------+-------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+-----------+---------+--------------------+-------+-----------------------------+
| 1 | PRIMARY | r02 | range | key | key | 4 | NULL | 27056 | Using where |
| 2 | DEPENDENT SUBQUERY | r03 | ref | recid_r02 | recid_r02 | 4 | reg00003.r02.RECID | 3 | Using where; Using filesort |
+----+--------------------+-------+-------+---------------+-----------+---------+--------------------+-------+-----------------------------+
2 rows in set (0.00 sec)
and, actually, query is much faster when it is used:
mysql> SELECT r02.*, (SELECT r03.r_datum FROM r03 FORCE INDEX(recid_r02) WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9))) ORDER BY r03.r_datum DESC LIMIT 1 ) AS last_order FROM r02 WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE) ORDER BY r02.auftrag DESC LIMIT 50;
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
| RECID | DELETED | AUFTRAG | NACHTRAG | KURZBEZ | FLAGS | last_order |
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
| 12803 | 0 | 50001 | 0 | Mustervorlage fr Dokumentation | 4096 | NULL |
...
| 30399 | 0 | 42209 | 0 | Studentenversion | 768 | NULL |
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
50 rows in set (0.48 sec)
mysql> SELECT r02.*, (SELECT r03.r_datum FROM r03 WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9))) ORDER BY r03.r_datum DESC LIMIT 1 ) AS last_order FROM r02 WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE) ORDER BY r02.auftrag DESC LIMIT 50;
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
| RECID | DELETED | AUFTRAG | NACHTRAG | KURZBEZ | FLAGS | last_order |
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
| 12803 | 0 | 50001 | 0 | Mustervorlage fr Dokumentation | 4096 | NULL |
...
| 30399 | 0 | 42209 | 0 | Studentenversion | 768 | NULL |
+-------+---------+---------+----------+--------------------------------------------------+----------+------------+
50 rows in set (1 min 5.75 sec)
So, one minute instead of less than a second...
[21 Apr 2011 7:53]
Daniƫl van Eeden
As noted in support request 3-3357778341: - This also affects Linux x86-64, not only Microsoft Windows (XP,Vista) - This also affects version 5.5.8 (Enterprise), not only 5.1.35, 5.1.38-bzr Could this still be fixed in 5.5+ or should it target 5.6+?
[8 Oct 2012 15:31]
Paul DuBois
Noted in 5.6.8, 5.7.0 changelogs. For some queries involving ORDER BY, the optimizer chose the wrong index for accessing the table.
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.043 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: In version 5.0.77, the otimizer choose the index `recid_r02`, for the following select. In version 5.1.35 it's now `key6`. If i change: ORDER BY r03.r_datum DESC to: ORDER BY r03.recid_r02, r03.r_datum DESC the index is correct. It seems that the optimizer did not mention that i did not use the field `r03.r_datum` in the where clause. SELECT r02.*, (SELECT r03.r_datum FROM r03 WHERE ((r03.recid_r02 = r02.recid) AND (r03.texttype IN (4,7,8,9))) ORDER BY r03.r_datum DESC LIMIT 1 ) AS last_order FROM r02 WHERE (r02.auftrag > 0) AND (r02.deleted = FALSE) ORDER BY r02.auftrag DESC LIMIT 50 Tables: CREATE TABLE `r02` ( `recid` int(11) NOT NULL DEFAULT '0', `deleted` tinyint(1) NOT NULL DEFAULT '0', `auftrag` int(11) NOT NULL DEFAULT '0', `nachtrag` int(11) NOT NULL DEFAULT '0', `kurzbez` varchar(60) COLLATE latin1_general_ci NOT NULL, `flags` bigint(20) NOT NULL DEFAULT '0', PRIMARY KEY (`recid`), UNIQUE KEY `key` (`auftrag`,`nachtrag`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; CREATE TABLE `r03` ( `recid` int(11) NOT NULL DEFAULT '0', `recid_r02` int(11) NOT NULL DEFAULT '0', `deleted` tinyint(1) NOT NULL DEFAULT '0', `auftrag` int(11) NOT NULL DEFAULT '0', `nachtrag` int(11) NOT NULL DEFAULT '0', `texttype` int(11) NOT NULL DEFAULT '0', `nummer` int(11) NOT NULL DEFAULT '0', `rechn_nr` varchar(20) COLLATE latin1_general_ci DEFAULT NULL, `doku_nr` varchar(20) COLLATE latin1_general_ci DEFAULT NULL, `betrag` double NOT NULL DEFAULT '0', `r_datum` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`recid`), UNIQUE KEY `key` (`auftrag`,`nachtrag`,`texttype`,`nummer`,`deleted`), UNIQUE KEY `key2` (`rechn_nr`), UNIQUE KEY `key3` (`doku_nr`), KEY `key6` (`r_datum`), KEY `recid_r02` (`recid_r02`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; How to repeat: create the tables r02 and r03. I've got 30000 records in r02 and 90000 record in r03.