MySQL 索引提示:FORCE INDEX
本文讲述如何在 MySQL 中强制查询优化器使用指定的命名索引。
有时候,虽然你创建了索引,但是你的 SQL 语句却不一定使用索引。 这是因为 MySQL 查询优化器的做出了它认为的更优的选择。
MySQL 查询优化器是 MySQL 数据库服务器的一个组件,它为 SQL 语句制定最佳执行计划。
但是,您可以是使用 FORCE INDEX
子句告诉 MySQL 查询优化器必须使用指定的索引。
MySQL FORCE INDEX
语法
要让 SQL 语句强制使用指定的缩影,请按照下面语法使用 FORCE INDEX
子句:
SELECT *
FROM table_name
FORCE INDEX (index_list)
WHERE condition;
说明:
- 请将
FORCE INDEX
子句放在FROM
子句之后。 - MySQL 查询优化器必须使用索引列表
index_list
中的一个索引。
MySQL FORCE INDEX
实例
我们将使用 Sakila 示例数据库中的 film
表进行演示。
以下是 film
表的定义:
DESC film;
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------------------------+
| film_id | smallint unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(128) | NO | MUL | NULL | |
| description | text | YES | | NULL | |
| release_year | year | YES | | NULL | |
| language_id | tinyint unsigned | NO | MUL | NULL | |
| original_language_id | tinyint unsigned | YES | MUL | NULL | |
| rental_duration | tinyint unsigned | NO | | 3 | |
| rental_rate | decimal(4,2) | NO | | 4.99 | |
| length | smallint unsigned | YES | | NULL | |
| replacement_cost | decimal(5,2) | NO | | 19.99 | |
| rating | enum('G','PG','PG-13','R','NC-17') | YES | | G | |
| special_features | set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') | YES | | NULL | |
| last_update | timestamp | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------------------------+
13 rows in set (0.01 sec)
以下语句显示了 film
表的索引:
SHOW INDEXES FROM film;
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| film | 0 | PRIMARY | 1 | film_id | A | 1000 | NULL | NULL | | BTREE | | | YES | NULL |
| film | 1 | idx_title | 1 | title | A | 1000 | NULL | NULL | | BTREE | | | YES | NULL |
| film | 1 | idx_fk_language_id | 1 | language_id | A | 1 | NULL | NULL | | BTREE | | | YES | NULL |
| film | 1 | idx_fk_original_language_id | 1 | original_language_id | A | 1 | NULL | NULL | YES | BTREE | | | YES | NULL |
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.00 sec)
这里,我们发现,建立在 language_id
列上的索引 是 idx_fk_language_id
。
要查找语言为英语的影片,请使用以下语句:
SELECT *
FROM film
WHERE language_id = 1;
要查看该语句的执行计划,请使用 EXPLAIN
语句:
EXPLAIN
SELECT *
FROM film
WHERE language_id = 1;
+----+-------------+-------+------------+------+--------------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+--------------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | film | NULL | ALL | idx_fk_language_id | NULL | NULL | NULL | 1000 | 100.00 | Using where |
+----+-------------+-------+------------+------+--------------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
这里, MySQL 查询优化器并没有使用 idx_fk_language_id
索引。这是因为 film
表中的所有影片都是英文影片,因此 MySQL 查询优化器指定全表扫描。
要强制查询优化器使用 idx_fk_language_id
索引,请使用以下带有 FORCE INDEX
的查询。以下语句展示了执行计划:
EXPLAIN
SELECT *
FROM film
FORCE INDEX (idx_fk_language_id)
WHERE language_id = 1;
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | film | NULL | ref | idx_fk_language_id | idx_fk_language_id | 1 | const | 1000 | 100.00 | NULL |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
现在, MySQL 查询优化器使用了 idx_fk_language_id
索引。
结论
MySQL FORCE INDEX
子句告诉 MySQL 查询优化器必须使用指定的索引。