MySQL在使用内存表时是否(cond,a,b)不一致?

MySQL在使用内存表时是否(cond,a,b)不一致?,mysql,Mysql,我在MySQL中查询表时得到一些不一致的结果。为了演示,我已经尽可能地精简了代码 drop table if exists numberfill; create table numberfill ( id INT not null primary key auto_increment ) Engine=MEMORY; drop procedure if exists populate; DELIMITER $$ CREATE PROCEDURE populate(numberRows

我在MySQL中查询表时得到一些不一致的结果。为了演示,我已经尽可能地精简了代码

drop table if exists numberfill;
create table numberfill (
    id INT not null primary key auto_increment
) Engine=MEMORY;

drop procedure if exists populate;
DELIMITER $$
CREATE PROCEDURE populate(numberRows INT)
BEGIN
    DECLARE counter INT;
    SET counter = 1;
    WHILE counter <= numberRows DO
        INSERT INTO
            numberfill
        SELECT
            counter;
        SET counter = counter + 1;
    END WHILE;
END
$$
DELIMITER ;

start transaction;
call populate(5000);
commit;

select if(a = 1, 5, 0), if(a = 1, 0, 5)
from (select cast(round(rand()) as unsigned) as a from numberfill) k;
似乎如果我不从numberfill中选择,查询会给出一致的结果。然而,当我从numberfill表中选择时,我得到了混合的结果。一些行给出0,0,其他行给出5,5,其他行给出5,0或0,5


有人知道为什么会这样吗?这是一个MySQL问题还是我正在做一些导致未定义行为的事情?我想这可能和兰德公司生产浮点数有关

这条评论太长了

你得到的是5,0和0,5的混合物,这很有道理。您正在用5000个数字填充一张表。然后,子查询将随机数0或1分配给每一行。这应该具体化,因此设置了值

因此,您的逻辑不可能得到0、0或5、5


较新版本的MySQL可能会发现,实现子查询是不必要的,而且它们可能会对rand条件进行两次评估。如果您得到的是0、0或5、5,那么可能就是这种情况。

当您多次引用某个值时,就会出现此问题。显然,MySql v 5.7决定根据其定义重新计算a,即再次执行rand以检索a的值

它与内存选项无关,也与if功能无关。以下查询将在每行中返回两个不同的值:

select a, a
from (select rand() as a from numberfill) k
可以通过将rand指定给变量,并为列别名a选择该变量来避免这种情况:

该查询将始终返回两个值相同的记录

强制实现评估的另一种方法是,使用高于numberfill中行数的值对内部查询设置限制:


另请参见。

是的,我得到了0,0和5,5。所以本质上你说的是MySQL正在做一些优化,这是错误地为每一行的“a”选择不同的值。“我想我只能用另一种方式来攻击它了。”尚特里·卡吉尔。两个建议。尝试在视图中放置rand表达式。尝试第二层子查询。后者可能会迫使MySQL实现中间结果。MySQL是否保证列的求值顺序?换言之,是否保证@a:=rand将在@a作为a之前进行评估?不,我不知道任何评估顺序的保证,但根据我的经验,我从未见过它以不同的顺序进行评估。实际上,我可以从选择@a:=randBool作为a从numberfill k中选择ifa=1,5,0,ifa=1,0,5;事实上,这将使评估顺序变得无关紧要。您还可以向子查询添加限制,而不使用变量。请参阅更新的答案。完全不相关,但请注意,作为参考,启动事务和提交对内存表没有影响,内存表不是事务表。@Michael sqlbot感谢您的提示。
select a, a
from (select @a:=rand() as a from numberfill) k
select a, a
from (select rand() as a from numberfill limit 9999999999) k