【发布时间】:2017-11-04 07:20:02
【问题描述】:
我正在做一个子查询,其中我有一个涉及随机数生成的计算列。在基本查询中,我选择了此列两次。 MySQL 5.6 按我的预期工作,计算值被调用一次并修复。 5.7+/8.0+ 执行似乎为每个选择单独重新评估子查询的列值。这是正确的行为吗?我可以做些什么来强制它在较新版本的 MySQL 中按预期工作?
CREATE TABLE t (
`id` BIGINT(20) NOT NULL PRIMARY KEY AUTO_INCREMENT
) ENGINE=InnoDB;
insert into t values();
insert into t values();
insert into t values();
insert into t values();
insert into t values();
SELECT
q.i,
q.r,
q.r
FROM (
SELECT
id AS i,
(FLOOR(RAND(100) * 4)) AS r
FROM t
) q;
MySQL 5.6 产生(值相同):
+---+-----+-----+
| i | r | r |
+---+-----+-----+
| 1 | 0 | 0 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 2 | 2 |
| 5 | 1 | 1 |
+---+-----+-----+
而 5.7 的产量(值不同):
+---+-----+-----+
| i | r | r |
+---+-----+-----+
| 1 | 0 | 2 |
| 2 | 3 | 2 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
| 5 | 2 | 0 |
+---+-----+-----+
【问题讨论】:
-
也许这取决于子查询是否物化。看起来您可以使用提示 /*+ SUBQUERY(MATERIALIZATION) */ (在您的内部选择之后添加)强制在 5.7 中实现(我希望这会让您获得 5.6 的行为)
-
Oracle 说它不是bug。他们或多或少说优化器可以忽略优化查询的不确定性。但是他们自己的文档说非确定性函数会阻碍优化,所以我怀疑它们不符合 SQL 标准,当我阅读了我的参考文献后,我会发布答案。请参阅 MySQL 12.6.2 Mathematical Functions 和 8.2.1.17 Function Call Optimization
-
回想起来,我的链接错误是 re ORDER BY RAND(),所以它不适用。 MySQL RAND() 文档说它在每个 WHERE 行中调用一次,并说明(但实际上并没有说)它在每个 SELECT 行中调用一次(并说它不能在 GROUP BY 或 ORDER BY 中使用;并且 ON & HAVING 未解决,但它们是根据 WHERE 定义的)。 (它也没有阐明一个子句中的多个调用。)将这一点添加到查询的 SQL 概念执行中,即 SELECT 子句应从 FROM 的输出中选择,这会成为一个错误。
-
@philipxy 我在 MySQL 提交了相应的bug report。
-
我同意我的仅供参考是一个单独的问题。但是,无论对多个文本调用给出什么合理的行为,您的双重选择子句都有 none。遗憾的是,MySQL 文档并没有说明在给定程序文本的情况下您可以依赖什么来实现非确定性功能。也不是变量——他们谈论某种涉及“客户端”的执行模型,但他们没有解释那个。
标签: mysql sql subquery materialized-views derived-table