Following is the table and index information for which I have the queries at the end.
Create Table: CREATE TABLE `food` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`page_no` int(11) DEFAULT NULL,
`nid` int(11) DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`source` varchar(4) CHARACTER SET utf8 NOT NULL,
`brand` varchar(500) CHARACTER SET utf8 DEFAULT NULL,
`cuisine` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`subcuisine` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`type` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`per_nr` float DEFAULT NULL,
`category` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`source_category` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`source_parent_category` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
KEY `id_idx` (`id`),
KEY `page_no_idx` (`page_no`),
KEY `source_idx` (`source`),
KEY `nid_idx` (`nid`),
KEY `per_nr_idx` (`per_nr`),
KEY `per_nr_source_category_nid_idx` (`per_nr`,`source_category`,`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
EXPLAIN 1
mysql > EXPLAIN SELECT food.nid, name, brand, cuisine, source_category, subcuisine, course, per_nr FROM food where category is not null and per_nr is not null and nid is not null;
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | food | ALL | nid_idx,per_nr_idx,per_nr_source_category_nid_idx | NULL | NULL | NULL | 532752 | Using where |
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
EXPLAIN 2
mysql > EXPLAIN SELECT name, nid, brand, cuisine, type, subcuisine, course, per_nr, source, source_category FROM food where per_nr>47 and source_category='Cereal Grains and Pasta' and food.nid!=205014 and food.nid is not null;
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | food | ALL | nid_idx,per_nr_idx,per_nr_source_category_nid_idx | NULL | NULL | NULL | 532752 | Using where |
+----+-------------+-------+------+---------------------------------------------------+------+---------+------+--------+-------------+
1 row in set (0.09 sec)
Queries:
- Explain 1: As we can see the query contains column name which are indexed as well, but still explain show that the mysql was not able to identify key to make it faster.
- Explain 2: I have created combined index per_nr_source_category_nid_idx in the same order in which the fields are available in where clause but still the mysql couldn't identify the index.
Although I have created indexes but still why system is not able to use it. This is my question in both the above queries.
Detailed Index details
mysql> SHOW INDEX FROM food;
+-------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| food | 1 | id_idx | 1 | id | A | 822286 | NULL | NULL | | BTREE | | |
| food | 1 | page_no_idx | 1 | page_no | A | 822286 | NULL | NULL | YES | BTREE | | |
| food | 1 | source_idx | 1 | source | A | 27 | NULL | NULL | | BTREE | | |
| food | 1 | nid_idx | 1 | nid | A | 822286 | NULL | NULL | YES | BTREE | | |
| food | 1 | per_nr_idx | 1 | per_nr | A | 27 | NULL | NULL | YES | BTREE | | |
| food | 1 | per_nr_source_category_nid_idx | 1 | per_nr | A | 27 | NULL | NULL | YES | BTREE | | |
| food | 1 | per_nr_source_category_nid_idx | 2 | source_category | A | 12092 | NULL | NULL | YES | BTREE | | |
| food | 1 | per_nr_source_category_nid_idx | 3 | nid | A | 822286 | NULL | NULL | YES | BTREE | | |
+-------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
8 rows in set (4.35 sec)
Best Answer
The order you put the conditions in the
WHERE
clause doesn't matter. But whether the conditions are=
or<>
orIS NULL
does matter in combination with the order of columns in composite indexes. To clear this out:So, for your first query which has a condition:
whatever order you put the columns in the composite index, a full index scan will be needed. The optimizer, seeing that the selectivity of this operation will be very low (meaning that even after the index scan it will still have a very high percentage of the rows passing the condition and all those rows will have to be retrieved from the table, decides to do a full scan of the table. And that is probably the best way to execute the query.
For the second query which has a condition:
we'll get rid of the redundant
food.nid IS NOT NULL
(if it is different than205014
, it cannot beNULL
anyway) and we'll order the conditions according to the above chart:This gives us a very useful hint about how to create the composite index:
So, add the 4th (or the 2nd) index:
if you want the second query to be executed efficiently: