对 MySQL 5.7/8.0 与 MySQL 5.6 中的每个重复选择重新评估子查询的 rand() 列

Subquery#39;s rand() column re-evaluated for every repeated selection in MySQL 5.7/8.0 vs MySQL 5.6(对 MySQL 5.7/8.0 与 MySQL 5.6 中的每个重复选择重新评估子查询的 rand() 列)
本文介绍了对 MySQL 5.7/8.0 与 MySQL 5.6 中的每个重复选择重新评估子查询的 rand() 列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个子查询,其中我有一个涉及随机数生成的计算列.在基本查询中,我选择了此列两次.MySQL 5.6 按我的预期工作,计算值被调用一次并修复.5.7+/8.0+ 执行似乎为每个选择单独重新评估子查询的列值.这是正确的行为吗?我可以做些什么来强制它在较新版本的 MySQL 中按预期工作?

I am doing a subquery in which I have a calculated column involving random number generation. In the base query I select this column twice. MySQL 5.6 works as I expect, the calculated value being called once and fixed. The 5.7+/8.0+ execution seems to re-evaluate the subquery's column value individually for each selection. Is this correct behavior? What can I do to force it work as expected in newer versions of 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 产生(值相同):

MySQL 5.6 yields (values are the same):

+---+-----+-----+
| i |  r  |  r  |
+---+-----+-----+
| 1 |   0 |   0 |
| 2 |   2 |   2 |
| 3 |   3 |   3 |
| 4 |   2 |   2 |
| 5 |   1 |   1 |
+---+-----+-----+

而 5.7 的产量(值不同):

while 5.7 yields (values are different):

+---+-----+-----+
| i |  r  |  r  |
+---+-----+-----+
| 1 |   0 |   2 |
| 2 |   3 |   2 |
| 3 |   1 |   1 |
| 4 |   2 |   1 |
| 5 |   2 |   0 |
+---+-----+-----+

推荐答案

如 MySQL 8.0.0 Milestone Release 可用,

在 MySQL 5.6 及更早版本中,派生表始终是具体化的.在5.7,派生表在大多数情况下合并到外部查询中,并在某些情况下具体化.

In MySQL 5.6 and earlier, derived tables were always materialized. In 5.7, derived tables are merged into the outer query in most cases, and materialized in some cases.

...

通过优化器提示启用合并派生表或视图 (WL#9307) — Guilhem Bichot 的这项工作允许用户使用merge"和no_merge"提示控制是合并还是实现派生表或视图.

Enabling merging a derived table or view through a optimizer hint (WL#9307) — This work by Guilhem Bichot allows users to control whether a derived table or view will be merged or materialized using the "merge" and "no_merge" hints.

我想这是我在较新版本的 MySQL 中观察到的行为的原因.提到的提示可以与 MySQL 8.0 一起使用来强制 RAND() 只被调用一次:

I suppose that this is the cause of the behavior I am observing in newer versions of MySQL. The mentioned hint can be used with MySQL 8.0 to force RAND() be called only once:

SELECT  /* NO_MERGE(q) */
        q.i,
        q.r,
        q.r
FROM    (
        SELECT 
                id AS i,
                (FLOOR(RAND(100) * 4)) AS r
        FROM t
        ) AS q;

+---+-----+-----+
| i |  r  |  r  |
+---+-----+-----+
| 1 |   0 |   0 |
| 2 |   2 |   2 |
| 3 |   3 |   3 |
| 4 |   2 |   2 |
| 5 |   1 |   1 |
+---+-----+-----+

然而,这在 5.7 中不可用.要在 5.7 中实现所需的行为,请将 LIMIT <a very high number> 添加到派生表定义中(我在下面使用带符号的 LONG_MAX).感谢 Roy Lyseng 提供的解决方法.

This however is not available in 5.7. To achieve the desired behavior with 5.7, add LIMIT <a very high number> to the derived table definition (I'm using signed LONG_MAX below). Thanks to Roy Lyseng for this workaround.

SELECT
        q.i,
        q.r,
        q.r
FROM    (
        SELECT 
                id AS i,
                (FLOOR(RAND(100) * 4)) AS r
        FROM t LIMIT 9223372036854775807
        ) AS q;

+---+-----+-----+
| i |  r  |  r  |
+---+-----+-----+
| 1 |   0 |   0 |
| 2 |   2 |   2 |
| 3 |   3 |   3 |
| 4 |   2 |   2 |
| 5 |   1 |   1 |
+---+-----+-----+

正如评论中提到的philipxy,无论是否应用了任何优化,都必须严格定义查询表达式的结果.这意味着它是 MySQL 5.7/8.0 中的优化器错误.

As philipxy mentioned in the comment, the result of a query expression must be strictly defined regardless of any optimizations being applied. Which means it is an optimizer bug in MySQL 5.7/8.0.

这篇关于对 MySQL 5.7/8.0 与 MySQL 5.6 中的每个重复选择重新评估子查询的 rand() 列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Execute complex raw SQL query in EF6(在EF6中执行复杂的原始SQL查询)
Hibernate reactive No Vert.x context active in aws rds(AWS RDS中的休眠反应性非Vert.x上下文处于活动状态)
Bulk insert with mysql2 and NodeJs throws 500(使用mysql2和NodeJS的大容量插入抛出500)
Flask + PyMySQL giving error no attribute #39;settimeout#39;(FlASK+PyMySQL给出错误,没有属性#39;setTimeout#39;)
auto_increment column for a group of rows?(一组行的AUTO_INCREMENT列?)
Sort by ID DESC(按ID代码排序)