I am creating a table that has a unique key constraint and I performing a select query on that table. MySQL does not use the index for the unique key for querying that. Why is that happening?
CREATE TABLE foo (
column1 int NOT NULL,
column2 int NOT NULL,
UNIQUE KEY idx_column1_column2 (column1, column2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
mysql> explain select * from foo where column1=1 and column2=1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | no matching row in const table |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show index from foo;
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| foo | 0 | idx_column1_column2 | 1 | column1 | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| foo | 0 | idx_column1_column2 | 2 | column2 | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.01 sec)
I would expect here that the idx_column1_column2 index be used for my select query but it's not why is that happening, how can I get it to use that index automatically?
Related
The Table
https://codex.wordpress.org/Database_Description
CREATE TABLE wp_terms (
term_id bigint(20) unsigned auto_increment,
name varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
slug varchar(200),
term_group bigint(10) DEFAULT 0,
PRIMARY KEY ( term_id )
) ENGINE=InnoDB;
The Index
MySQL> show index from wp_terms;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| wp_terms | 1 | name | 1 | name | A | 716638 | 191 | NULL | | BTREE | | | YES | NULL |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
The Query
MySQL> select name from wp_terms order by name limit 1;
+--------------------+
| name |
+--------------------+
| **************** |
+--------------------+
1 row in set (0.83 sec)
The Explain
MySQL> explain select name from wp_terms order by name limit 1;
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| 1 | SIMPLE | wp_terms | NULL | ALL | NULL | NULL | NULL | NULL | 802726 | 100.00 | Using filesort |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
The Question
Why isn't the 'name' index even a possible key? Forcing it had no effect.
Thank you in advance.
Thanks to #Dai for pointing out the issue. 'name' was an index prefix, not a full index. Creating a full index on name resulted in index being used for the query.
MySQL> alter table wp_terms add index(name);
MySQL> explain select name from wp_terms order by name limit 1;
+----+-------------+----------+------------+-------+---------------+--------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+---------------+--------+---------+------+------+----------+-------------+
| 1 | SIMPLE | wp_terms | NULL | index | NULL | name_2 | 802 | NULL | 1 | 100.00 | Using index |
+----+-------------+----------+------------+-------+---------------+--------+---------+------+------+----------+-------------+
Thank you!
I have a schema with tables like this (simplified):
-------- --------------- ------------
| key | | permission | | resource |
|------| |-------------| |----------|
| id | -----< | id | >----- | id |
| name | | key_id | | name |
-------- | resource_id | ------------
| action |
---------------
The permission table definition script is something like this:
CREATE TABLE `permission` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`key_id` INT(11) NOT NULL,
`resource_id` INT(11) NOT NULL,
`action` VARCHAR(32) NOT NULL,
PRIMARY_KEY (`id`),
CONSTRAINT `fk_permission_key` FOREIGN KEY (`key_id`) REFERENCES `key` (`id`),
CONSTRAINT `fk_permission_resource` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
This all works fine. Then, I decided I needed a unique constraint on the permission table so that only a single record can exist for an action/key/resource combination, so I do this:
ALTER TABLE `permission` ADD UNIQUE KEY `uq_permission` (`key_id`, `resource_id`, `action`);
This also works fine. We are in an environment where we use migrations to manage schema changes, so I want to make sure that there's a "roll back" script. But when I issue this command:
ALTER TABLE `permission` DROP INDEX `uq_permission`;
I get this error:
1553 - Cannot drop index 'uq_permission': needed in a foreign key
constraint
After some fuddling around, I found that if I dropped the foreign key fk_permission_key, I am then able to drop the unique constraint.
Why is my unique constraint getting tangled up with a completely separate foreign key?
When you add the fk_permission_key constraint, MySQL automatically creates an index (this behaviour differs from other database engines, where you need to create such indexes explicitly):
mysql> SHOW INDEX FROM `permission`;
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| permission | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_key | 1 | key_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_resource | 1 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.00 sec)
When you create the uq_permission index, MySQL apparently drops the fk_permission_key index because it understands it can use your own index.
mysql> SHOW INDEX FROM `permission`;
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| permission | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 1 | key_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 2 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 3 | action | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_resource | 1 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
5 rows in set (0.01 sec)
However, if you now attempt to remove uq_permission MySQL complaints because the foreign key will no longer have a usable index (and this time it isn't smart enough to create the index automatically).
I don't know if automatic index creation is configurable but, in this case, the only solution I can think of is to provide the index yourself:
mysql> ALTER TABLE `permission` ADD INDEX `fk_permission_key` (`key_id`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW INDEX FROM `permission`;
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| permission | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 1 | key_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 2 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 0 | uq_permission | 3 | action | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_resource | 1 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_key | 1 | key_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
6 rows in set (0.01 sec)
mysql> ALTER TABLE `permission` DROP INDEX `uq_permission`;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW INDEX FROM `permission`;
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| permission | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_resource | 1 | resource_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| permission | 1 | fk_permission_key | 1 | key_id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.00 sec)
Automatic index creation is documented:
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later if you create
another index that can be used to enforce the foreign key
constraint. index_name, if given, is used as described previously.
I have a mysql table voucher_codes with the following schema:
mysql> describe voucher_codes;
+--------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(10) unsigned | YES | MUL | NULL | |
| promo_code | varchar(30) | YES | MUL | NULL | |
| voucher_value | double | NO | | NULL | |
| date_created | datetime(6) | NO | | NULL | |
| date_modified | datetime(6) | NO | | NULL | |
| redeem_flag | tinyint(1) | NO | | NULL | |
| fk_voucher_rule_id | int(11) | NO | MUL | NULL | |
+--------------------+------------------+------+-----+---------+----------------+
The indexes defined on the table are as follows:
mysql> show index from voucher_codes;
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| voucher_codes | 0 | PRIMARY | 1 | id | A | 15280692 | NULL | NULL | | BTREE | | |
| voucher_codes | 1 | voucher_codes_user_id | 1 | user_id | A | 2805369 | NULL | NULL | YES | BTREE | | |
| voucher_codes | 1 | voucher_codes_promo_code | 1 | promo_code | A | 7389780 | NULL | NULL | YES | BTREE | | |
| voucher_codes | 1 | fk_voucher_rule_id | 1 | fk_voucher_rule_id | A | 60 | NULL | NULL | | BTREE | | |
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
The numbers of records with voucher_code 1 and redeem_flag as 0 and 1 are as follows:
mysql> select count(*) from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1;
+----------+
| count(*) |
+----------+
| 135114 |
+----------+
1 row in set (3.17 sec)
mysql> select count(*) from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1;
+----------+
| count(*) |
+----------+
| 1575024 |
+----------+
1 row in set (2.56 sec)
There are 1.5+ million records with redeem_flag as 1 and 100k+ are 0.
But the query with redeem_flag as 1 takes less time as compared with query with redeem_flag 0.
Below are the results:
mysql> select promo_code from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1 limit 1 ;
+--------------+
| promo_code |
+--------------+
| XXXXXXXXXX |
+--------------+
1 row in set (3.67 sec)
mysql> explain select promo_code from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1 limit 1 ;
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| 1 | SIMPLE | voucher_codes | NULL | ref | fk_voucher_rule_id | fk_voucher_rule_id | 4 | const | 3258352 | 10.00 | Using where |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Query with redeem_flag as 1:
mysql> select promo_code from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1 limit 1 ;
+------------+
| promo_code |
+------------+
| XXXXXXXXX |
+------------+
1 row in set (0.00 sec)
mysql> explain select promo_code from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1 limit 1 ;
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| 1 | SIMPLE | voucher_codes | NULL | ref | fk_voucher_rule_id | fk_voucher_rule_id | 4 | const | 3258352 | 10.00 | Using where |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Unable to understand this behaviour. Even though the index fk_voucher_rule_id is getting used, but it is taking more time with records which are more as compared to less number of records.
Update: Adding show create table result:
mysql> show create table voucher_codes;
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| voucher_codes | CREATE TABLE `voucher_codes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned DEFAULT NULL,
`promo_code` varchar(30) DEFAULT NULL,
`voucher_value` double NOT NULL,
`date_created` datetime(6) NOT NULL,
`date_modified` datetime(6) NOT NULL,
`redeem_flag` tinyint(1) NOT NULL,
`fk_voucher_rule_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `voucher_codes_user_id` (`user_id`),
KEY `voucher_codes_promo_code` (`promo_code`),
KEY `fk_voucher_rule_id` (`fk_voucher_rule_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16305657 DEFAULT CHARSET=latin1 |
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
First of all, test speed of your queries using SELECT SQL_NO_CACHE ... instead of just SELECT .... It is quite odd that query runs in 0.00 time.
Furthermore, create a composite index on redeem_flag, fk_voucher_rule and then retest your queries for comparison.
NOTE: You should use same order of fields in a query as it is in your index. Also, as #Raymod Nijland said, remove redundant indices. For example, if you have index fk_voucher_rule, redeem_flag it will be used both for queries that use only fk_voucher_rule and fk_voucher_rule, redeem_flag queries (other way around does not apply, you can't use it only for querying redeem_flag).
I have a table of over 9 million rows. I have a SELECT query that I'm using an index for. Here is the query:
SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 9259466
AND `tried` = 0
LIMIT 1;
That query executes very fast (0.00 sec). Here is the explain for that query:
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
| 1 | SIMPLE | 04c1Tg0M | range | PRIMARY,triedex | PRIMARY | 4 | NULL | 10822 | Using where |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
Now here is the same query except that I'm going to change the id to 6259466:
SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 5986551
AND `tried` = 0
LIMIT 1;
That query took 4.78 seconds to complete. This is the problem. Here is the explain for that query:
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
| 1 | SIMPLE | 04c1Tg0M | ref | PRIMARY,triedex | triedex | 2 | const | 9275107 | Using where |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
What is happening here and how can I fix it? Here are my indexes:
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 04c1Tg0M | 0 | PRIMARY | 1 | id | A | 9275093 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 1 | username | A | 9275093 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 2 | id | A | 9275093 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 3 | tried | A | 9275093 | NULL | NULL | YES | BTREE | |
| 04c1Tg0M | 1 | triedex | 1 | tried | A | 0 | NULL | NULL | YES | BTREE | |
| 04c1Tg0M | 1 | triedex | 2 | id | A | 9275093 | NULL | NULL | | BTREE | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
And here is my table structure:
| 04c1Tg0M | CREATE TABLE `04c1Tg0M` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`tried` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `pdex` (`username`,`id`,`tried`),
KEY `triedex` (`tried`,`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8 |
The first SQL returns 10822 rows, while the second one returns 9275107 rows!
The use of primary key "id" index in the second query isn't so useful because you have to do a full table scan anyway.
MySQL's cost-based optimizer thinks, in the case of the 2nd query, it's better off to use the index on 'tried'.
If you have to do a full table-scan, you're better off not using an index, as index constitutes additional disk reads.
You can use "use index" or "force index" in your query to hint to the optimizer whether to use an index.
Also update the statistics by analyzing your table periodically so the cost-based optimizer is working correctly.
I have the following InnoDB table, which acts kinda weird under MySQL 5.1.49
(mysql Ver 14.14 Distrib 5.1.49, for debian-linux-gnu (x86_64) using readline 6.1)
mysql> desc forum_favorite;
+-----------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------------+------+-----+---------+-------+
| id_member | smallint(5) unsigned | YES | MUL | NULL | |
| id_topic | int(10) unsigned | YES | MUL | NULL | |
+-----------+----------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> show index from forum_favorite;
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| forum_favorite | 1 | id_member | 1 | id_member | A | 2134 | NULL | NULL | YES | BTREE | |
| forum_favorite | 1 | id_topic | 1 | id_topic | A | 3201 | NULL | NULL | YES | BTREE | |
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2 rows in set (0.00 sec)
Now, check the query:
mysql> SELECT id_topic FROM forum_favorite WHERE (id_member = 2);
+----------+
| id_topic |
+----------+
| 1249 |
| 20209 |
| 91878 |
| 99026 |
| 90257 |
| 1179 |
| 1179 |
+----------+
7 rows in set (0.00 sec)
When I search for a specific topic with a given member, it gives an empty result set. WHY?
mysql> select * from forum_favorite where id_member = 2 and id_topic = 1249;
Empty set (0.00 sec)
But when I search for another topic, it comes back ok...
It can be found without id_member in the where clause:
mysql> select * from forum_favorite where id_topic = 1249;
+-----------+----------+
| id_member | id_topic |
+-----------+----------+
| 2 | 1249 |
+-----------+----------+
1 rows in set (0.00 sec)
Indexes:
mysql> show index from forum_favorite;
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| forum_favorite | 1 | id_member | 1 | id_member | A | 2134 | NULL | NULL | YES | BTREE | |
| forum_favorite | 1 | id_topic | 1 | id_topic | A | 3201 | NULL | NULL | YES | BTREE | |
+----------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2 rows in set (0.00 sec)
Explain on the incriminating query:
mysql> explain select * from forum_favorite where id_member = 2 and id_topic = 1249;
+----+-------------+----------------+-------------+--------------------+--------------------+---------+------+------+---------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+-------------+--------------------+--------------------+---------+------+------+---------------------------------------------------------------+
| 1 | SIMPLE | forum_favorite | index_merge | id_member,id_topic | id_member,id_topic | 3,5 | NULL | 1 | Using intersect(id_member,id_topic); Using where; Using index |
+----+-------------+----------------+-------------+--------------------+--------------------+---------+------+------+---------------------------------------------------------------+
1 row in set (0.00 sec)
Explain on the query, with another topicid. WHAT THE HELL???
mysql> explain select * from forum_favorite where (id_member = 2) and id_topic = 20209;
+----+-------------+----------------+------+--------------------+----------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+--------------------+----------+---------+-------+------+-------------+
| 1 | SIMPLE | forum_favorite | ref | id_member,id_topic | id_topic | 5 | const | 1 | Using where |
+----+-------------+----------------+------+--------------------+----------+---------+-------+------+-------------+
1 row in set (0.00 sec
I have migrated from an old mysql 4.x database to mysql 5.1 recently, where the above queries gave consistent results.
What could be the problem?!?! What makes the optimizer go bonkers?
Have you tried to run OPTIMIZE on the table?
UPD:
For InnoDB tables, OPTIMIZE TABLE is mapped to ALTER TABLE, which rebuilds the table to update index statistics and free unused space in the clustered index.
I think the problem is actually in Using intersect(id_member,id_topic);. I would extend the id_topic index to (id_topic, id_member) so that it used a single key for the lookup instead of index merge (which is actually rather rare in MySQL).