我在向表中添加新索引时遇到了一些问题,我想知道为什么MySQL没有使用新索引.

我注意到,只有当我的SELECT语句请求其他不属于索引的列时才会发生这种情况(例如,SELECT *不起作用,而SELECT id, otherId起作用).

有人能给我解释一下为什么MySQL Select 进行表扫描而不是使用索引吗?

架构数据库数据库

该表由多个列组成,即idotherId.id是我的主键,而otherId也应该被编入索引.otherId可以为空并且是唯一的.

model Entity {
    id      String  @id @default(cuid())
    otherId String? @unique
    // Few more ...
}

基数和 Select 性

SELECT
  COUNT(DISTINCT Entity.otherId) as cardinality,
  COUNT(*) as totalRows,
  COUNT(Entity.otherId) as nonNullRows,
  COUNT(DISTINCT Entity.otherId) / COUNT(*) as selectivity
FROM
  Entity
cardinality totalRows nonNullRows selectivity
171 1187 171 0.1441

展开SELECT*

这个没有使用索引,但我希望它会使用.

展开SELECT* FROM Entity WHERE Entity.otherId = ?;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE Entity ALL Entity_otherId_key 1187 10 Using where

解释SELECT ID、OtherID

这本书确实使用了索引.

解释SELECT ID、OtherID FROM Entity WHERE Entity.otherId = ?;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE Entity index Entity_otherId_key Entity_otherId_key 767 1187 10 Using where; Using index

显示索引

显示索引 from Entity;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression
Entity 0 PRIMARY 1 id A 1187 BTREE YES
Entity 0 Entity_otherId_key 1 otherId A 172 YES BTREE YES

MySQL版本

8.2.0

推荐答案

如果查询不执行行限制(WHERE子句)或排序(ORDER BY子句),则它将判断每一行.

这得到了两个EXPLAIN结果的rows列的支持.1187.第1187章第二次

但是type: ALLtype: index之间有什么区别呢?

第一个是表扫描.该查询将判断表中的每一行.由于MVCC,它必须这样做才能计算出它们的数量.因此,查询的成本与行数成正比.

第二个是指数扫描.这比表扫描稍好一些,但它仍然需要判断命名索引中的每个条目来对它们进行计数.成本也与行数成正比,但它可能能够判断更少的页来单独读取索引,而不是整个表.

EXPLAIN"Using index"中的注释会让您相信它是优化的.严格地说,它确实在这个查询中使用了索引,但它使用索引的方式与搜索或排序的方式不同.


在查询might使用索引进行行限制的情况下,优化器可以 Select 不这样做.一种常见的情况是,您搜索的特定值估计会出现在很大比例的行上.优化器决定先对该值进行索引查找,然后再进行第二次查找以获得该行,这可能比仅仅进行表扫描的成本更高,就好像不存在索引一样.

我们可以想到书后面的索引.为什么常用词没有编入索引?因为查找一个出现在许多页面上的常用词是不必要的开销.从头到尾阅读这本书需要做同样多的工作(即翻页).

就MySQL的优化器而言,如果优化器认为您要搜索的值出现在表中大约20%的行上,那么它很可能会跳过索引.此阈值未记录在案,可能会受到其他优化器分析的影响.这只是我观察到的一个粗略的门槛.

Mysql相关问答推荐

返回50%的随机结果

如何在使用VALUES()插入时指定jOOQ中的行别名

无法连接到扩展坞MySQL Unix套接字

我可以在姓名和姓名日期之间进行搜索吗?

排序子查询结果并返回每个 ID 的第一行

如何在 WampServer 上重新初始化 MySQL 以允许 lower_case_table_names = 2

获取 MySQL 中每一行之间负差的总和

在一个 SQL 查询中对同一列中相同类型的不同值求和

Select 多列但仅按 1 列分组

MySQL 查询组按日期(12 小时间隔)

动态创建内联 SQL 表(用于排除左连接)

MySQL 整数与日期时间索引

我的 PDO 声明不起作用

我可以在单个 Amazon RDS 实例上创建多少个数据库

MySQL 删除多列

MySQL - 错误 1045 - 访问被拒绝

使用 mysqldriver 连接数据库时出错

如何将数组存储到mysql中?

当运行 UPDATE ... datetime = NOW();所有更新的行都会有相同的日期/时间吗?

我在哪里可以下载 mysql jdbc jar?