从 5.5 升级到 mysql 5.7,MyISAM 到 InnoDB,LEFT JOIN 和 NULL 问题

Upgrade to mysql 5.7 from 5.5, MyISAM to InnoDB, LEFT JOIN and NULL issue

我最近将带有 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。

此行为与我升级前的行为不同,后者的查询运行良好。我假设某处存在某种逻辑错误,但我无法弄清楚。任何帮助将不胜感激!!

我觉得你的查询没问题。但是,你可以简化它:

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 中的列。另一个是使用变量的表达式的求值顺序。你的代码没有这些,但也许你的原始代码有一些可疑之处。

您发现了一个错误,优化器在知道 left join 是否有任何结果之前直接获取文字。它是一个已知错误的衍生物, Bug #77707 Right outer join return wrong result when literal expression involvedleft join 版本与此合并)。

据说已在 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)

由于(新)文件排序有其自己的优化器,该错误似乎仍然存在并在使用 order by 时重新出现(之前,它发生在有或没有排序的情况下)。

发送错误报告。

为了让你的查询工作,你可以(除了 Gordons 重写的代码)通过使用

...
LEFT JOIN (SELECT suggestion, 
           case when student = student then 1 else null end AS voted 
           FROM shop_suggestion_votes WHERE student = 60910) AS voted 
...