mysql - 为什么 MySQL 更喜欢使用文件排序进行索引范围扫描而不是索引查找

标签 mysql database indexing query-optimization

给出的是这个查询和索引

create table entries
(
    id                        bigint auto_increment
        primary key,
    parent_entries_id         bigint                                 null,
    group_type                varchar(16)                            not null,
    quantity                  int                                    not null,
    -- a couple of other columns
    created_at                datetime     default CURRENT_TIMESTAMP null,
    modified_at               datetime                               null on update CURRENT_TIMESTAMP,
    constraint FK_396C2CCA677190CC
        foreign key (parent_entries_id) references parent_entries (id)
)
    collate = utf8_unicode_ci;

create index idx_1 on entries (quantity, group_type);
create index idx_2 on entries (group_type, quantity);

我想统计数量大于 0 的所有条目,并按类型分组:

SELECT COUNT(*), group_type
FROM entries
WHERE quantity > 0
GROUP BY group_type;

我希望使用 idx_2,因为它应该仅通过索引查找/迭代来提供所有数据,无需其他操作,并且解释计划支持我的想法:

     type, key_len,      rows, filtered, Extra
idx_1: range,  '4',   667_780,   100, 'Using where; Using index; Using temporary; Using filesort'
idx_2: index, '54', 4_218_471, 33.33, 'Using where; Using index'

但是如果我在不强制索引的情况下运行查询,数据库将使用 idx_1 (带有临时表和文件排序 - 是的,它实际上有点慢),我不明白为什么?这是我的第一个案例,USE INDEX 子句实际上会有帮助吗?

最佳答案

如果您的 WHERE amount > 0 过滤器是一个相等过滤器,那么您的第一个索引将很好地加速此查询。它将找到正确的 GROUP BY 值顺序来扫描索引并生成结果,而无需任何排序。但这不是你的情况。

根据 DBMS 的确切品牌和版本,您也许能够在 ((quantity > 0), group_type) 上创建函数索引,从而为您的查询获得完美的覆盖索引。

否则,您将需要索引扫描或表扫描以及文件排序。 filesort 的命名略有错误。它不是文件系统文件,而是需要排序的临时表状对象。如果它们变得非常大,就会溢出到磁盘文件,但这种情况很少见。

我建议您信任查询规划器(DBMS 的一部分,被使用 Oracle 的住宅区居民称为“基于成本的优化器”),而不是强制使用索引。只要您在批量加载后执行分析表条目,查询规划器就会做出可靠且具有 future 弹性的工作来决定是使用索引更快还是仅扫描表更快。

关于mysql - 为什么 MySQL 更喜欢使用文件排序进行索引范围扫描而不是索引查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77409986/

相关文章:

php - 将列与数据数组进行比较

mysql - 静态资源的访问控制

python - 使用两个 bool 数组索引 2D np.array 时出现意外行为

javascript - 在 Json 对象中搜索元素

mysql - 像这样创建一个日历数据库表

php - Json数组数据在php中插入空值

mysql - Liquibase 主键在 H2 上创建了两次

mysql - 确定要删除的 MySQL 行数以达到目标数据库大小

java - 关闭和打开数据库连接?

mysql - KEY 关键字是什么意思?