【发布时间】:2020-08-10 14:16:46
【问题描述】:
我有以下疑问:
select *
from test_table
where app_id = 521
and is_deleted=0
and category in (7650)
AND created_timestamp >= '2020-07-28 18:19:26'
AND created_timestamp <= '2020-08-04 18:19:26'
ORDER BY created_timestamp desc
limit 30
所有四个字段,app_id、is_deleted、category 和 created_timestamp 都被索引。但是,app_id 和 is_deleted 的基数非常小(各 3 个)。
category 字段分布均匀,但 created_timestamp 似乎是此查询的一个非常好的索引选择。
但是,MySQL 没有使用created_timestamp 索引,因此需要 4 秒才能返回。如果我强制 MySQL 使用 USE INDEX (created_timestamp) 使用 created_timestamp 索引,它会在 40 毫秒内返回。
我检查了解释命令的输出以了解发生这种情况的原因,发现 MySQL 正在使用以下参数执行查询:
自动索引决策,耗时 > 4s
type: index_merge
key: category,app_id,is_deleted
rows: 10250
filtered: 0.36
Using intersect(category,app_id,is_deleted); Using where; Using filesort
强制索引使用:
Use index created_timestamp, takes < 50ms
type: range
key: created_timestamp
rows: 47000
filtered: 0.50
Using index condition; Using where; Backward index scan
MySQL 可能认为扫描的行数越少越好,这也是有道理的,但是为什么在这种情况下查询需要永远返回呢?如何修复此查询?
【问题讨论】:
-
Using intersect就像做三个查询,找到表的几个子集,找到所有三个子集中都存在的行。您应该考虑按该顺序在(app_id, is_deleted, created_timestamp, category)上定义多列索引。 -
@BillKarwin - 如果
IN有多个值,我可能会同意您的订购。当只有一个id时,会优化为=,此时,category明显优于日期范围。 -
@RickJames Putting
created_timestamp首先消除了文件排序。第四列无论哪种方式都不能作为 SQL 层查找进行搜索,但至少可以通过 InnoDB 索引条件下推进行过滤。 -
@BillKarwin - 对于
category IN (7650),其优化与category = 7650相同,它将通过category。 -
我假设它在查询的一般情况下会有多个值。