目录

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 查询优化器必须使用指定的索引。