MySQL Index Hint:USE INDEX
This article describes how to use the USE INDEX
to recommend MySQL query optimizer use specified named indexes.
The MySQL query optimizer is a component of the MySQL database server that formulates the best execution plan for SQL statements. The MySQL optimizer usually bases its decisions on index cardinality. Sometimes, although you have created an index, your SQL statement does not necessarily use the index. This is because the MySQL query optimizer made what it thought was a better choice.
MySQL allows you to use the USE INDEX
clause to advise the query optimizer to use specific named indexes.
However, it is still possible that the MySQL query optimizer does not apply the index you suggest. If you want MySQL to use the index you specify, use the FORCE INDEX
clause.
If the query optimizer is using a wrong index, USE INDEX
is useful.
MySQL USE INDEX
syntax
To give an index hint with MySQL USE INDEX
, follow the syntax:
SELECT column_list
FROM table_name
USE INDEX (index_list)
WHERE condition;
Explanation:
- Put the
USE INDEX
clause after theFROM
clause. - If the MySQL query optimizer is going to use an index, it must use one of the indexes in the
index_list
list.
Note that the query optimizer will not necessarily use the named index you suggest.
MySQL USE INDEX example
We’ll use the customer
table from the Sakila sample database for demonstration.
Take a look at the definition of the actor
table:
DESC customer;
+-------------+-------------------+------+-----+-------------------+-----------------------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------------+------+-----+-------------------+-----------------------------------------------+
| customer_id | smallint unsigned | NO | PRI | NULL | auto_increment |
| store_id | tinyint unsigned | NO | MUL | NULL | |
| first_name | varchar(45) | NO | | NULL | |
| last_name | varchar(45) | NO | MUL | NULL | |
| email | varchar(50) | YES | | NULL | |
| address_id | smallint unsigned | NO | MUL | NULL | |
| active | tinyint(1) | NO | | 1 | |
| create_date | datetime | NO | | NULL | |
| last_update | timestamp | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+-------------+-------------------+------+-----+-------------------+-----------------------------------------------+
9 rows in set (0.00 sec)
Let’s create two indexes,
CREATE INDEX idx_last_name
ON customer (last_name);
CREATE INDEX idx_last_name_first_name
ON customer (last_name, first_name);
Take a look at the indexes in the customer
table:
SHOW INDEXES FROM customer;
+----------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| customer | 0 | PRIMARY | 1 | customer_id | A | 599 | NULL | NULL | | BTREE | | | YES | NULL |
| customer | 1 | idx_fk_store_id | 1 | store_id | A | 2 | NULL | NULL | | BTREE | | | YES | NULL |
| customer | 1 | idx_fk_address_id | 1 | address_id | A | 599 | NULL | NULL | | BTREE | | | YES | NULL |
| customer | 1 | idx_last_name | 1 | last_name | A | 598 | NULL | NULL | | BTREE | | | YES | NULL |
| customer | 1 | idx_last_name_first_name | 1 | last_name | A | 598 | NULL | NULL | | BTREE | | | YES | NULL |
| customer | 1 | idx_last_name_first_name | 2 | first_name | A | 599 | NULL | NULL | | BTREE | | | YES | NULL |
+----------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
6 rows in set (0.00 sec)
Use the EXPLAIN
statement to view the execution plan of the following statement whose last name is BARBEE
:
EXPLAIN
SELECT *
FROM customer
WHERE last_name = 'BARBEE';
+----+-------------+----------+------------+------+----------------------------------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+----------------------------------------+---------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | customer | NULL | ref | idx_last_name,idx_last_name_first_name | idx_last_name | 182 | const | 1 | 100.00 | NULL |
+----+-------------+----------+------------+------+----------------------------------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
As you can see from the output, the MySQL query optimizer chose to use the idx_last_name
index.
If you think it is better to use idx_last_name_first_name
, specify it using USE INDEX
, as follows:
EXPLAIN
SELECT *
FROM customer
USE INDEX (idx_last_name_first_name)
WHERE last_name = 'BARBEE';
+----+-------------+----------+------------+------+--------------------------+--------------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+--------------------------+--------------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | customer | NULL | ref | idx_last_name_first_name | idx_last_name_first_name | 182 | const | 1 | 100.00 | NULL |
+----+-------------+----------+------------+------+--------------------------+--------------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
Note that this is for demonstration purposes only, and not optimal.
As you can see from the output, the MySQL query optimizer chose to use the idx_last_name_first_name
index.
Conclusion
This article discusses the basic usage of MySQL USE INDEX
index hints. USE INDEX
is different from FORCE INDEX
:
USE INDEX
tell MySQL to use one of the indexes in the list for this query, but MySQL may not use it.FORCE INDEX
force MySQL to use a specific index.