仅查询索引字段时在 EXPLAIN 的额外列中获取 "Using where; Using index"
Getting "Using where; Using index" in Extra column of EXPLAIN when only querying indexed fields
当运行以下查询时:
EXPLAIN SELECT
belgarath.match_oc_history.id_, belgarath.match_oc_history.tour_id
FROM
belgarath.match_oc_history
JOIN
belgarath.tournament_oc ON belgarath.tournament_oc.tour_id = belgarath.match_oc_history.tour_id
AND belgarath.tournament_oc.orig_id = belgarath.match_oc_history.tournament_oc_orig_id;
我得到以下 table:
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
| 1 | SIMPLE | tournament_oc | NULL | index | uq__tournament_oc__tour_id__orig_id,ix__tournament_oc__tour_id,ix__tournament_oc__orig_id | uq__tournament_oc__tour_id__orig_id | 6 | NULL | 26550 | 100 | Using where; Using index |
| 1 | SIMPLE | match_oc_history | NULL | ref | ix__match_oc_history__five_keys,ix__match_oc_history__tour_id,fk__match_oc_history__player_oc_p1_idx,fk__match_oc_history__player_oc_p2_idx,fk__match_oc_history__tour_id__tournament_oc_orig_id | fk__match_oc_history__tour_id__tournament_oc_orig_id | 5 | belgarath.tournament_oc.tour_id,belgarath.tournament_oc.orig_id | 54 | 100 | Using index |
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
我从周围阅读的理解是,如果查询只使用索引字段,那么它不需要使用 where
。这是正确的吗?
如果是,那为什么我会在 EXPLAIN
table 中看到它弹出?
如果不是,我应该担心在这种情况下使用 where
吗?我一直认为 where
比 index
...
慢
Table 作文:
CREATE TABLE `tournament_oc` (
`updated` timestamp NULL DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`id_` int NOT NULL AUTO_INCREMENT,
`tour_id` tinyint DEFAULT NULL,
`orig_id` int NOT NULL,
PRIMARY KEY (`id_`),
UNIQUE KEY `uq__tournament_oc__tour_id__orig_id` (`tour_id`,`orig_id`),
KEY `ix__tournament_oc__tour_id` (`tour_id`),
KEY `ix__tournament_oc__orig_id` (`orig_id`),
CONSTRAINT `fk__tournament_oc__tour_id` FOREIGN KEY (`tour_id`) REFERENCES `tour` (`id_`)
) ENGINE=InnoDB AUTO_INCREMENT=27788 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
CREATE TABLE `match_oc_history` (
`updated` timestamp NULL DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`id_` int NOT NULL AUTO_INCREMENT,
`tour_id` tinyint NOT NULL,
`tournament_oc_orig_id` int NOT NULL,
`round_oc_id` tinyint NOT NULL,
`player_oc_orig_id_p1` int NOT NULL,
`player_oc_orig_id_p2` int NOT NULL,
PRIMARY KEY (`id_`),
KEY `ix__match_oc_history__five_keys` (`tour_id`,`tournament_oc_orig_id`,`round_oc_id`,`player_oc_orig_id_p1`,`player_oc_orig_id_p2`),
KEY `ix__match_oc_history__round_oc_id` (`round_oc_id`),
KEY `ix__match_oc_history__tour_id` (`tour_id`),
KEY `fk__match_oc_history__player_oc_p1_idx` (`tour_id`,`player_oc_orig_id_p1`),
KEY `fk__match_oc_history__player_oc_p2_idx` (`tour_id`,`player_oc_orig_id_p2`),
KEY `fk__match_oc_history__tour_id__tournament_oc_orig_id` (`tour_id`,`tournament_oc_orig_id`),
CONSTRAINT `fk__match_oc_history__player_oc_p1` FOREIGN KEY (`tour_id`, `player_oc_orig_id_p1`) REFERENCES `player_oc` (`tour_id`, `orig_id`),
CONSTRAINT `fk__match_oc_history__player_oc_p2` FOREIGN KEY (`tour_id`, `player_oc_orig_id_p2`) REFERENCES `player_oc` (`tour_id`, `orig_id`),
CONSTRAINT `fk__match_oc_history__round_oc_id` FOREIGN KEY (`round_oc_id`) REFERENCES `round_oc` (`id_`),
CONSTRAINT `fk__match_oc_history__tour_id` FOREIGN KEY (`tour_id`) REFERENCES `tour` (`id_`),
CONSTRAINT `fk__match_oc_history__tournament_oc` FOREIGN KEY (`tour_id`, `tournament_oc_orig_id`) REFERENCES `tournament_oc` (`tour_id`, `orig_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1516084 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
根据评论:
SHOW WARNINGS
语句响应:
/* select#1 */ select `belgarath`.`match_oc_history`.`id_` AS `id_`,`belgarath`.`match_oc_history`.`tour_id` AS `tour_id` from `belgarath`.`match_oc_history` join `belgarath`.`tournament_oc` where ((`belgarath`.`match_oc_history`.`tournament_oc_orig_id` = `belgarath`.`tournament_oc`.`orig_id`) and (`belgarath`.`match_oc_history`.`tour_id` = `belgarath`.`tournament_oc`.`tour_id`))
Using index
意味着整个查询(至少对于有问题的 table)不需要除 INDEX
中的任何列。这比必须在索引的 BTree 和数据的 BTree 之间来回跳动要快。
- 优化器可以自由地重新排序
JOINed
table,因为它认为合适。 EXPLAIN
反映了优化器的决定。
- “警告”显示了它如何决定执行查询。
OR
在解析的时候经常会变成WHERE
。 (您使用 ON
是正确的,因为这就是 table 的关联方式。)
- 没有真正的
WHERE
,优化器 [通常] 选择较小的 table,然后执行“嵌套循环连接”(NLJ) 以进入下一个 table。这通常是执行查询的更快方法。我认为不需要 STRAIGHT_JOIN
;相信优化器。
- 您拥有最佳复合索引,可以让优化器首先选择 table 中的一个。
- 你认为 'wrong' table 为什么先?
- “Using where”意义不大;忽略它。
- “where is slower than index”——这没有意义。带有 suitable 索引的
WHERE
子句 将使查询 运行 更快。 ON
子句几乎总是需要一个索引来 运行 更快。 (你所拥有的实际上是 ON
。)
当运行以下查询时:
EXPLAIN SELECT
belgarath.match_oc_history.id_, belgarath.match_oc_history.tour_id
FROM
belgarath.match_oc_history
JOIN
belgarath.tournament_oc ON belgarath.tournament_oc.tour_id = belgarath.match_oc_history.tour_id
AND belgarath.tournament_oc.orig_id = belgarath.match_oc_history.tournament_oc_orig_id;
我得到以下 table:
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
| 1 | SIMPLE | tournament_oc | NULL | index | uq__tournament_oc__tour_id__orig_id,ix__tournament_oc__tour_id,ix__tournament_oc__orig_id | uq__tournament_oc__tour_id__orig_id | 6 | NULL | 26550 | 100 | Using where; Using index |
| 1 | SIMPLE | match_oc_history | NULL | ref | ix__match_oc_history__five_keys,ix__match_oc_history__tour_id,fk__match_oc_history__player_oc_p1_idx,fk__match_oc_history__player_oc_p2_idx,fk__match_oc_history__tour_id__tournament_oc_orig_id | fk__match_oc_history__tour_id__tournament_oc_orig_id | 5 | belgarath.tournament_oc.tour_id,belgarath.tournament_oc.orig_id | 54 | 100 | Using index |
+----+-------------+------------------+------------+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+---------+-----------------------------------------------------------------+-------+----------+--------------------------+
我从周围阅读的理解是,如果查询只使用索引字段,那么它不需要使用 where
。这是正确的吗?
如果是,那为什么我会在 EXPLAIN
table 中看到它弹出?
如果不是,我应该担心在这种情况下使用 where
吗?我一直认为 where
比 index
...
Table 作文:
CREATE TABLE `tournament_oc` (
`updated` timestamp NULL DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`id_` int NOT NULL AUTO_INCREMENT,
`tour_id` tinyint DEFAULT NULL,
`orig_id` int NOT NULL,
PRIMARY KEY (`id_`),
UNIQUE KEY `uq__tournament_oc__tour_id__orig_id` (`tour_id`,`orig_id`),
KEY `ix__tournament_oc__tour_id` (`tour_id`),
KEY `ix__tournament_oc__orig_id` (`orig_id`),
CONSTRAINT `fk__tournament_oc__tour_id` FOREIGN KEY (`tour_id`) REFERENCES `tour` (`id_`)
) ENGINE=InnoDB AUTO_INCREMENT=27788 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
CREATE TABLE `match_oc_history` (
`updated` timestamp NULL DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`id_` int NOT NULL AUTO_INCREMENT,
`tour_id` tinyint NOT NULL,
`tournament_oc_orig_id` int NOT NULL,
`round_oc_id` tinyint NOT NULL,
`player_oc_orig_id_p1` int NOT NULL,
`player_oc_orig_id_p2` int NOT NULL,
PRIMARY KEY (`id_`),
KEY `ix__match_oc_history__five_keys` (`tour_id`,`tournament_oc_orig_id`,`round_oc_id`,`player_oc_orig_id_p1`,`player_oc_orig_id_p2`),
KEY `ix__match_oc_history__round_oc_id` (`round_oc_id`),
KEY `ix__match_oc_history__tour_id` (`tour_id`),
KEY `fk__match_oc_history__player_oc_p1_idx` (`tour_id`,`player_oc_orig_id_p1`),
KEY `fk__match_oc_history__player_oc_p2_idx` (`tour_id`,`player_oc_orig_id_p2`),
KEY `fk__match_oc_history__tour_id__tournament_oc_orig_id` (`tour_id`,`tournament_oc_orig_id`),
CONSTRAINT `fk__match_oc_history__player_oc_p1` FOREIGN KEY (`tour_id`, `player_oc_orig_id_p1`) REFERENCES `player_oc` (`tour_id`, `orig_id`),
CONSTRAINT `fk__match_oc_history__player_oc_p2` FOREIGN KEY (`tour_id`, `player_oc_orig_id_p2`) REFERENCES `player_oc` (`tour_id`, `orig_id`),
CONSTRAINT `fk__match_oc_history__round_oc_id` FOREIGN KEY (`round_oc_id`) REFERENCES `round_oc` (`id_`),
CONSTRAINT `fk__match_oc_history__tour_id` FOREIGN KEY (`tour_id`) REFERENCES `tour` (`id_`),
CONSTRAINT `fk__match_oc_history__tournament_oc` FOREIGN KEY (`tour_id`, `tournament_oc_orig_id`) REFERENCES `tournament_oc` (`tour_id`, `orig_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1516084 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
根据评论:
SHOW WARNINGS
语句响应:
/* select#1 */ select `belgarath`.`match_oc_history`.`id_` AS `id_`,`belgarath`.`match_oc_history`.`tour_id` AS `tour_id` from `belgarath`.`match_oc_history` join `belgarath`.`tournament_oc` where ((`belgarath`.`match_oc_history`.`tournament_oc_orig_id` = `belgarath`.`tournament_oc`.`orig_id`) and (`belgarath`.`match_oc_history`.`tour_id` = `belgarath`.`tournament_oc`.`tour_id`))
Using index
意味着整个查询(至少对于有问题的 table)不需要除INDEX
中的任何列。这比必须在索引的 BTree 和数据的 BTree 之间来回跳动要快。- 优化器可以自由地重新排序
JOINed
table,因为它认为合适。EXPLAIN
反映了优化器的决定。 - “警告”显示了它如何决定执行查询。
OR
在解析的时候经常会变成WHERE
。 (您使用ON
是正确的,因为这就是 table 的关联方式。)- 没有真正的
WHERE
,优化器 [通常] 选择较小的 table,然后执行“嵌套循环连接”(NLJ) 以进入下一个 table。这通常是执行查询的更快方法。我认为不需要STRAIGHT_JOIN
;相信优化器。 - 您拥有最佳复合索引,可以让优化器首先选择 table 中的一个。
- 你认为 'wrong' table 为什么先?
- “Using where”意义不大;忽略它。
- “where is slower than index”——这没有意义。带有 suitable 索引的
WHERE
子句 将使查询 运行 更快。ON
子句几乎总是需要一个索引来 运行 更快。 (你所拥有的实际上是ON
。)