我们正在将我们的数据库系统从 MySQL 5.6 升级到 MySQL 5.7,并且自从升级以来,一些查询的运行速度非常慢。
经过一番调查,我们将其范围缩小到一些 JOIN 查询,这些查询在使用“大于”> 或“小于”< 运算符时突然不再听“WHERE”子句。使用 '=' 运算符时,它确实按预期工作。当查询一个大表时,这会导致持续 100% 的 CPU 使用率。
查询已被简化以解释手头的问题;使用解释时,我们得到以下输出:
explain
select * from TableA as A
left join
(
select
DATE_FORMAT(created_at,'%H:%i:00') as `time`
FROM
TableB
WHERE
created_at < DATE_ADD(CURDATE(), INTERVAL -3 HOUR)
)
as V ON V.time = A.time
输出
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 SIMPLE TableB NULL index created_at created_at 4 NULL 488389 100.00 Using where; Using index; Using join buffer (Block Nested Loop)
如您所见,它正在查询/匹配488389行而不使用 where 子句,因为这是该表中的总记录。
现在运行相同的查询,但使用LIMIT 99999999命令或使用“=”运算符:
explain
select * from TableA as A
left join
(
select
DATE_FORMAT(created_at,'%H:%i:00') as `time`
FROM
TableB
WHERE
created_at < DATE_ADD(CURDATE(), INTERVAL -3 HOUR) LIMIT 999999999
)
as V ON V.time = A.time
输出
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 244194 100.00 Using where; Using join buffer (Block Nested Loop)
2 DERIVED TableB NULL range created_at created_at 4 NULL 244194 100.00 Using where; Using index
您可以看到它突然只匹配作为表的一部分的 '244194' 行,或者使用 '=' 运算符:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 SIMPLE TableB NULL ref created_at created_at 4 const 1 100.00 Using where; Using index
正如预期的那样,只有 1 行。
所以现在的问题是,我们是否一直在以错误的方式查询,只是在升级时才发现,还是自 MySQL 5.6 以来发生了变化?=运算符起作用似乎很奇怪,但由于某种原因, < 和>被忽略了,除非使用 LIMIT?..
我们四处搜索,找不到这个问题的原因,出于显而易见的原因,我们宁愿不在我们的代码中使用限制 9999999 的解决方案。
注意当只在连接内运行查询时,它也可以按预期工作。
注意我们还在 MariaDB 10.1 上运行了相同的测试,同样的问题。