给出的是这个查询和索引
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 quantity > 0
过滤器是相等过滤器,那么您的第一个索引将很好地加速此查询。但这不是你的情况。
根据 DBMS 的确切品牌和版本,您也许能够在
((quantity > 0), group_type)
上创建函数索引,从而为您的查询获得完美的覆盖索引。
否则,您将需要索引扫描或表扫描以及文件排序。 filesort 的命名略有错误。它不是文件系统文件,而是需要排序的临时表状对象。如果它们变得非常大,就会溢出到磁盘文件,但这种情况很少见。
我建议您信任查询规划器(DBMS 的一部分,被使用 Oracle 的住宅区居民称为“基于成本的优化器”),而不是强制使用索引。只要您在批量加载后执行
ANALYZE TABLE entries
,查询规划器就会做出可靠的工作来决定是使用索引更快还是简单地扫描表。