背景
2021 MySQL 各个版本发布的时间点如下表,从上面的表格可以看到 MySQL-8.0.24 只存续了 21 天,那是什么造就了它如此短命?
MySQL-8.0.23 | MySQL-8.0.24 | MySQL-8.0.25 | MySQL-8.0.26 | MySQL-8.0.27 |
|---|---|---|---|---|
2021-01-18 | 2021-04-20 | 2021-05-11 | 2021-07-20 | 2021-10-19 |
从一个 BUG 说起
对于一个程序来说在一些单射(单射函数)场景下,我们认为,当我们的输入变量改变的时候,输出也随着改变,但是 MySQL-8.0.24 在这里翻车了。
第一步 确认版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.24 |
+-----------+第二步 添加测试数据
create database tempdb;
use tempdb;
create table t(x smallint);
insert into t(x) values (32767),(14742),(14743);
mysql> select * from t order by x;
+-------+
| x |
+-------+
| 14742 |
| 14743 |
| 32767 |
+-------+
3 rows in set (0.00 sec)/* 因为之后会有到这个两条 SQL 来演示 BUG,所以在这时先执行一下看结果 */
/* 47510 = 14743 + 32767 */
mysql> select sum(x) from t where x>14742;
+--------+
| sum(x) |
+--------+
| 47510 |
+--------+
1 row in set (0.00 sec)
/* 由于没有数比 32767 大所以返回 NULL */
mysql> select sum(x) from t where x>32767;
+--------+
| sum(x) |
+--------+
| NULL |
+--------+
1 row in set (0.00 sec)到目前为止我们对数据的求和都是正常的,好戏马上就要开始了,因为只是换了一种写法 MySQL 执行的结果就不对了。
第三步 复现 BUG
由于这个 BUG 出在了动态 SQL 这里,所以如果我们想要复现 BUG 就要用动态 SQL 来重写我们上面已经写过的求和逻辑。
mysql> prepare stmt from 'select sum(x) from t where x > ?;';
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> set @foo=14742;
Query OK, 0 rows affected (0.00 sec)
mysql> execute stmt using @foo;
+--------+
| sum(x) |
+--------+
| 47510 |
+--------+
1 row in set (0.00 sec)
/* ---------------------------------------------*/
/* 改变输入的参数值 ,但是输出沿用的上一次的输出 */
/* 理论上这里是要返回 NULL 的,但是它返回了上一步的结果 */
mysql> set @foo=32767;
Query OK, 0 rows affected (0.00 sec)
mysql> execute stmt using @foo;
+--------+
| sum(x) |
+--------+
| 47510 |
+--------+
1 row in set (0.00 sec)可以看到当我们第二次执行 stmt 时,虽然参数值发生了变化,但是返回的结果没有变(返回了上一次执行的结果)。
最后
从官方的 BUG 记录来看,8.0.23 就有这个问题了,只是在 8.0.24 发布几天后把这个 BUG 给修了,搞的 8.0.24 成了最今年最短命的版本。