我最近使用MyISAM表将数据库从MySQL 5.5更新到MySQL 5.7 InnoDB表。大多数事情都做得很好,但是有一些特殊的查询会产生奇怪的结果。
背景:建议首先获得批准,然后可以投票。在批准之前,只有建议者才能看到建议。
查询:
SELECT description, suggested_by, voted, votes
FROM shop_suggestions s
LEFT JOIN (SELECT suggestion, 1 AS voted FROM shop_suggestion_votes WHERE student = 60910) AS voted ON (voted.suggestion = s.id)
LEFT JOIN (SELECT suggestion, COUNT(student) AS votes FROM shop_suggestion_votes GROUP BY suggestion) AS votes ON (votes.suggestion = s.id)
WHERE approved > 0 OR suggested_by = 60910 ORDER BY votes
真正奇怪的是,当ORDER BY votes
部分存在时,投票的值始终为1,而如果它保持不变,那么它的预期值为NULL有人没有投票。
此行为与我升级之前的行为不同,后者的查询工作正常。我假设某处存在某种逻辑错误,但我无法弄明白。任何帮助将不胜感激!!
答案 0 :(得分:1)
您的查询对我来说很合适。但是,你可以简化它:
SELECT description, suggested_by, voted, votes
FROM shop_suggestions s LEFT JOIN
(SELECT suggestion, COUNT(student) as votes,
MAX(student = 60910) as voted
FROM shop_suggestion_votes
GROUP BY suggestion
) votes
ON (votes.suggestion = s.id)
WHERE approved > 0 OR suggested_by = 60910
ORDER BY votes;
如果我不得不推测实际问题,我猜你会过度简化查询并删除了有问题的问题。记录的一些常见(错误)使用的MySQL功能并不总是有效,但无论如何都会使用它们。我们想到的是使用select
中不在group by
中的列。另一种是使用变量的表达式的评估顺序。你的代码中没有这些,但也许你的原始代码有可疑的东西。
答案 1 :(得分:1)
You found a bug where the optimizer takes a literal directly before knowing if the left join
has any results. It is a derivate of a known bug,
Bug #77707 Right outer join return wrong result when literal expression involved (the left join
-version got merged with this).
It was supposedly fixed in 5.7.8,
Incorrect results could be produced tor views and derived tables on the inner side of an outer join and from which non-nullable expressions such as literals were selected. (Bug #73953, Bug #20841369, Bug #67014, Bug #15967464, Bug #65936, Bug #14358878, Bug #67300, Bug #15936817, Bug #76327, Bug #20708288)
Since the (new) filesort has its own optimizer, it seems the bug still persists there and resurfaces when using order by
(before, it happened with or without ordering).
Send a bug report.
To make your query work, you can (apart from Gordons rewritten code) trick mysql into evaluating something (and thus not optimizing the literal away) by using e.g.
...
LEFT JOIN (SELECT suggestion,
case when student = student then 1 else null end AS voted
FROM shop_suggestion_votes WHERE student = 60910) AS voted
...