给出以下两个问题:
查询#1
SELECT log.id
FROM log
WHERE user_id IN
(188858, 188886, 189854, 203623, 204072)
and type in (14, 15, 17)
ORDER BY log.id DESC
LIMIT 25 OFFSET 0;
查询#2-4 ID而不是5
SELECT log.id
FROM log
WHERE user_id IN
(188858, 188886, 189854, 203623)
and type in (14, 15, 17)
ORDER BY log.id DESC
LIMIT 25 OFFSET 0;
解释计划
-- Query #1
1 SIMPLE log range idx_user_id_and_log_id idx_user_id_and_log_id 4 41280 Using index condition; Using where; Using filesort
-- Query #2
1 SIMPLE log index idx_user_id_and_log_id PRIMARY 4 53534 Using where
为什么添加一个id会使执行计划如此不同?我说的是毫秒到1分钟的时间差。我想这可能和 eq_range_index_dive_limit
参数,但它仍然小于10(默认值)。我知道我可以强制使用索引而不是 clustered index
,但我想知道mysql为什么这么做。
我应该试着去理解吗?或者有时不可能理解查询计划器的决策?
额外细节
表大小:11gb
行:1.08亿
mysql:5.6.7版本
从in子句中删除哪个id无关紧要。
索引: idx_user_id_and_log_id(user_id, id)
3条答案
按热度按时间gpnt7bae1#
添加
每一个都是一个“覆盖”索引。因此,整个查询可以通过只查看一个索引来执行,而不涉及“数据”。
对于优化器,我有两个选择——希望它能够选择
user_id IN (...)
更具选择性或type IN (...)
为了挑选更好的指标。如果,在添加这些之后,您对
idx_user_id_and_log_id(user_id, id)
,DROP
是的。(不,我无法解释为什么查询2选择进行表扫描。)
omvjsjqw2#
加入更有效。
使用in运算符的值创建临时表。然后在表“log”和临时值表之间建立连接。
有关更多信息,请参阅此答案。
8hhllhi23#
如您所示,mysql有两种可选的查询计划用于
ORDER BY ... LIMIT n
:读取所有符合条件的行,对它们进行排序,然后从前面的n行中选择。
按排序顺序读取行,当找到n个符合条件的行时停止。
为了决定哪个选项更好,优化器需要估计where条件的过滤效果。这不是直截了当的,尤其是对于没有索引的列,或者对于值相关的列。在您的例子中,为了找到比优化器预期的前25个符合条件的行,可能需要按排序顺序读取更多的表。
在处理limit查询的方式上有了一些改进,这两种改进都出现在5.6的更高版本中(您运行的是预ga版本!),以及更新版本(5.7、8.0)。我建议您尝试升级到更高版本,看看这是否仍然是一个问题。
通常,如果您想了解查询规划器的决策,应该查看查询的优化器跟踪。