这是我的查询:
SELECT COUNT(1)
FROM nhd
WHERE gnis_id IN (01372336);
表定义上有一个
INDEX gnis_id (gnis_id)
,实际上,该索引用于此查询。但是当我用COUNT(1)
替换*
时,索引是not使用,至少根据EXPLAIN
。这是为什么?为什么更改我返回的列会改变 MySQL 决定将哪个索引用于查询的 WHERE 部分的方式?
这是
*
的 EXPLAIN 的输出:
id: 1
select_type: SIMPLE
table: nhd
partitions: NULL
type: ALL
possible_keys: gnis_id
key: NULL
key_len: NULL
ref: NULL
rows: 2752840
filtered: 10.00
Extra: Using where
这是
SHOW INDEX FROM nhd
的输出:
我正在运行 MySQL 8.0.33
从你的
SHOW INDEX
语句的结果,我们可以看到关于表条件的信息gnis_id
:
Table: nhd
Non_unique: 1
Key_name: gnis_id
Seq_in_index: 1
Column_name: gnis_id
Collation: A
Cardinality: 16206
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
正如基数所示,索引的选择性即基数/表行计数 16206 / 2752840 = 0.0059 非常低。并且通过使用
select *
,它的项目超出了索引的存储值,如果 MySQL 决定使用索引,它必须使用每个索引行末尾的聚集键来引用主表。 首先,使用
select gnis_id
而不是 select *
,这将使 MySQL 使用索引,因为索引覆盖了 gnis_id 本身的值,这意味着不需要额外的参考工作。您会发现执行计划中的访问类型为ref
,这使得查询响应时间明显优于由ALL
.引起的访问类型select *
select *
子句但在from子句的末尾添加force index(gnis_id)
强制MySQL使用索引。
SELECT *
FROM nhd force index(gnis_id)
WHERE gnis_id IN (01372336);
找出执行它需要多长时间,并比较在不强制索引的情况下执行它需要多长时间。你会明白为什么 MySQL 决定不使用索引。