没有LIMIT的MySQL 5.7 RAND()和IF()会导致意外结果

时间:2018-01-24 22:20:25

标签: mysql

我有以下查询

LIMIT 20

返回如下内容:

result with LIMIT

这正是你所期望的。但是,一旦我删除SELECT t.res, IF(t.res=0, "zero", "more than zero") FROM ( SELECT table.*, IF (RAND()<=0.2,1, IF (RAND()<=0.4,2, IF (RAND()<=0.6,3,0))) AS res FROM table) t 我收到了非常意外的结果(返回的行数超过20,我将其剪掉以便于阅读):

LIMIT

result without LIMIT

附注:
我正在使用MySQL 5.7.18-15-log,这是一个高度抽象的例子(真正的查询要困难得多) 我正在努力了解正在发生的事情。我不需要提供解决方案的答案,而没有任何解释为什么原始版本不起作用。谢谢。

更新GROUP BY id不是使用t.res = 0,而是在第一种情况下也适用。

更新2: 根据zerkms的要求,我在第二个示例中添加了t.res + 1和{{1}} result without LIMIT and two more columns

1 个答案:

答案 0 :(得分:2)

问题是由MySQL 5.7中引入的关于如何处理(子)查询中的派生表的变化引起的 基本上,为了优化性能,当您的子查询返回非确定性结果时,某些子查询会在不同的时间和/或多次执行,从而导致意外的结果(例如我的RAND()}。) 有两种简单(同样难看)的解决方法可以让MySQL实现&#34;实现&#34; (又称返回确定性结果)这些子查询:使用LIMIT <high number>GROUP BY id两者强制MySQL实现子查询并返回预期结果。
最后一个选项是在derived_merge变量optimizer_switch中关闭derived_merge=off(请确保保留所有其他参数)。

进一步阅读:
https://mysqlserverteam.com/derived-tables-in-mysql-5-7/
Subquery's rand() column re-evaluated for every repeated selection in MySQL 5.7/8.0 vs MySQL 5.6