给出以下两个查询:
查询#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决定这样做。
我应该尝试理解吗?还是有时候无法理解查询计划者的决定?
其他详细信息
idx_user_id_and_log_id(user_id, id)
答案 0 :(得分:2)
正如您所显示的,MySQL有两个替代查询计划,用于使用ORDER BY ... LIMIT n
的查询:
为了确定哪个是更好的选择,优化器需要估计WHERE条件的过滤效果。这不是直截了当的,特别是对于没有索引的列或与值相关的列。在您的情况下,为了找到前25个符合条件的行,可能要比排序程序读取更多的表,而不是优化程序期望的行。
在5.6的更高版本(您正在GA之前的版本中运行!)和较新的版本(5.7、8.0)中,对LIMIT查询的处理方式都有了一些改进。我建议您尝试升级到更高版本,看看是否仍然存在问题。
通常,如果您想了解查询计划者的决定,则应查看查询的优化器跟踪。
答案 1 :(得分:0)
答案 2 :(得分:0)
添加
INDEX(user_id, type, id),
INDEX(type, user_id, id)
每个都是“覆盖”索引。这样,整个查询可以通过仅查看一个索引来执行,而无需触摸“数据”。
对于Optimizer,我有两种选择-希望它可以选择user_id IN (...)
是更具选择性还是type IN (...)
以选择更好的索引。
如果在添加这些元素后idx_user_id_and_log_id(user_id, id)
,DROP
没有任何用途。
(不,我无法解释为什么查询2选择进行表扫描。)