MySQL:为什么 IN 子句中的第 5 个 ID 会彻底改变查询计划?

标签 mysql sql indexing query-performance

给定以下两个查询:

查询#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(默认值)。我知道我可以强制使用索引而不是聚集索引,但我想知道为什么 MySQL 会这样决定。

我应该尝试去理解吗?或者有时无法理解查询规划器的决策?

额外细节

  • 表大小:11GB
  • 行数:1.08 亿
  • MySQL:5.6.7
  • 从 IN 子句中删除哪个 ID 无关紧要。
  • 索引:idx_user_id_and_log_id(user_id, id)

最佳答案

正如您所展示的,MySQL 有两个可供选择的查询计划,用于使用 ORDER BY ... LIMIT n 的查询:

  1. 读取所有符合条件的行,对它们进行排序,然后选择 n 顶行。
  2. 按排序顺序读取行,并在找到 n 个符合条件的行时停止。

为了决定哪个是更好的选择,优化器需要估计你的WHERE条件的过滤效果。这不是直截了当的,特别是对于没有索引的列,或者对于值相关的列。在您的情况下,可能必须按排序顺序读取更多表才能找到比优化器预期的前 25 个符合条件的行。

在 5.6 的后续版本(您运行的是 pre-GA 版本!)和较新的版本(5.7、8.0)中,处理 LIMIT 查询的方式有了一些改进。我建议您尝试升级到更高版本,看看这是否仍然是一个问题。

一般来说,如果您想了解查询规划器的决策,您应该查看查询的优化器跟踪。

关于MySQL:为什么 IN 子句中的第 5 个 ID 会彻底改变查询计划?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51793915/

相关文章:

c# - 检索 BLOB 文件

MySQL - 非常简单的加入花费的时间太长

sql - RID 查找 - 逻辑搜索

SQL标准转义列名?

sql - 如何使用 NOW() 函数作为范围的上限?

MySQL优化查询

MySQL Join 语句将两个表中的数据放入 datagridview

java - 使用 MySQL 语法在 MySQL Workbench 中存储音频文件/文件路径

mysql - SQL 连接和排序

php - 使用 $_SESSION 超全局获取当前在线用户并稍后将其设置回当前 session 数据是否不好?