MySQL5.6升级8.0时用户自定义变量用法差异问题咨询
MySQL 5.6与8.0用户自定义变量执行结果差异原因
核心原因是两个版本的查询优化器执行策略不同,且MySQL本身未对非SET语句中的用户变量求值顺序做规范约束,具体逻辑如下:
- MySQL 5.6执行逻辑
5.6版本优化器不会对该类无关联子查询做谓词下推优化,执行顺序严格按照子查询优先、外层判断在后的流程执行:- 首先执行
FROM ( SELECT @t:=0 ) T子查询,完成@t的赋值操作,值为0 - 执行外层WHERE条件
@t IS NOT NULL,判断结果为真 - 返回
@t的值0,符合预期
- 首先执行
- MySQL 8.0执行逻辑
8.0版本优化器新增了更激进的谓词下推优化,会优先对不依赖子查询输出列的条件提前求值,减少无效扫描:- 优化器分析WHERE条件
@t IS NOT NULL,发现该条件不依赖子查询T的任何输出列,因此在执行子查询前就先判断该条件 - 此时
@t尚未赋值,值为NULL,条件判断结果为假 - 优化器直接判定无符合条件的行,不会执行子查询中的赋值逻辑,因此返回空集
- 优化器分析WHERE条件
官方说明:MySQL 文档始终明确标注,在SELECT等非SET语句中同时对用户自定义变量进行赋值和读取时,两者的执行顺序是不确定的,完全由优化器的执行计划决定。5.6版本的执行结果只是偶然符合预期,并非规范保证的行为,不能作为业务逻辑的稳定依赖。
兼容解决方案
如果需要保证变量赋值逻辑优先执行,可以选择两种调整方式:
- 给子查询增加LIMIT限制,强制子查询先物化,阻止谓词下推优化:
SELECT @t FROM ( SELECT @t:=0 LIMIT 1 ) T WHERE @t IS NOT NULL
- 拆分为两个独立语句,先完成变量赋值再执行查询,从根源上避免顺序问题:
SET @t:=0; SELECT @t WHERE @t IS NOT NULL;
内容的提问来源于stack exchange,提问作者veryslow
相关产品推荐
相关产品推荐

