MySQL 索引提示:FORCE INDEX
有时候,虽然你创建了索引,但是你的SQL语句却不一定使用索引。这是因为MySQL查询优化器的做出了它认为的更优的选择。MySQL查询优化器是MySQL数据库服务器的一个组件,它为SQL语句制定最佳执行计划。但是,您可以是使用FORCEINDEX子句告诉MySQL查询优化器必须使用指定的索引。MySQ
有时候,虽然你创建了索引,但是你的 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 查询优化器必须使用指定的索引。