首页 > 数据库 >再遇 MySQL “一招必杀” Bug

再遇 MySQL “一招必杀” Bug

时间:2023-08-28 23:32:02浏览次数:44  
标签:8.0 再遇 derived MySQL pushdown Bug condition

TL;DR

该 Bug 与 Derived Condition Pushdown Optimization 相关,从 MySQL 8.0.26 引入,8.0.27 和 8.0.28 仍受影响,直到 MySQL 8.0.29 被修复。 但是,MySQL 8.0.29 有其他致命缺陷,官网已经移除下载链接,建议升级到新版本 MySQL 8.0.33 或 MySQL 8.0.34。

问题现象

该问题是 vx 群里的好友发现的,在 MySQL 5.7、TiDB 中并未发现该问题,但当应用程序运行在 MySQL 8.0.27 时,问题出现,最终定位到具体 SQL,并提炼出最小化复现步骤,诱发问题的 SQL 如下。

SELECT 1
FROM (
  SELECT bb.c_int+1 AS c_int111
  FROM (
    SELECT aa.c_int AS c_int
    FROM (
      SELECT 0 AS c_int
    ) aa
  ) bb
) cc
WHERE c_int111 > 1
;

经过多版本实验比对,发现该 SQL 在较低版本(8.0.25 及以下)或较高版本(8.0.29 及以上)的 MySQL 中执行正常,在兼容 MySQL 5.7 协议的 TiDB 中执行正常,在 MariaDB 中也执行正常。

但是在 MySQL 8.0.27 / 8.0.28 中,该 SQL 执行异常。

But again, 在 MySQL 8.0.26 中,该 SQL 将导致 DB Crash,“一招致命”。

到此,可以确定,这是 MySQL 8.0.26 的一个 Bug,并对 MySQL 8.0.27 和 8.0.28 持续产生影响,直到 MySQL 8.0.29 被完整修复,恢复可用态。

Bug 确认

知道了 Bug 影响和被修复的版本,以及 crash log 就降低了寻找 Bug 号的难度。 对于 MySQL 社区版,除了搜索引擎,通常有三个途径可以用来找寻 Bug 号,分别是 MySQL 官网的 Release Notes,MySQL Bug 系统,以及 MySQL 社区版源码。

对于此案例,可以通过错误日志来快速定位,摘取重要日志如下。

/usr/sbin/mysqld(Condition_pushdown::replace_columns_in_cond(Item**, bool)+0x74) [0x55715b87c6e4]
/usr/sbin/mysqld(Condition_pushdown::make_cond_for_derived()+0x2a3) [0x55715b87d7f3]
/usr/sbin/mysqld(Query_block::push_conditions_to_derived_tables(THD*)+0xda) [0x558385bda21a]
/usr/sbin/mysqld(Query_block::prepare(THD*, mem_root_deque<Item*>*)+0xd7c) [0x558385bef7fc]

简单解释上面四个方法的含义:

    Condition_pushdown::replace_columns_in_cond:
    用派生表表达式替换将推入此派生表的条件中的列。
    Condition_pushdown::make_cond_for_derived:创建一个可以下推到派生表的条件,并将其下推。
    Query_block::push_conditions_to_derived_tables:将此查询块的WHERE条件的部分推送到物化派生表。
    Query_block::prepare:准备查询块进行优化。解析表和列信息。

在公开的 Bug 系统中找到了一条记录 (Bug #104574),S2 严重级别。

与之对应的 commit 记录为:518c2ae85b55f78565908567a02de55d0a8a477a

Bug#33197276: regression: Assertion `cur_query_block != select' failed.
and segfault in Condition_pushdown::replace_columns_in_cond
Bug#33209907: condition seems not correct

继续排查 sql_derived.cc 这个文件在 8.0.29 发版之前的提交信息,找到可能与之相关的 commit 记录。

顺藤摸瓜,找到了 MySQL 8.0.29 修复的那条 commit 记录 (3ca1c67dfdbc9e2972810773474fbfe70fdabaa8)。

WL#13730 - Condition pushdown to materialized derived tables
with set operations

回头再看 Release Notes,可以找到如下记录:

    MySQL 8.0.27
    In certain cases, the view reference cloned when pushing a condition down to a derived table was not always resolved in the desired context. In addition, a check for a null condition was not performed correctly. (Bug #104574, Bug #33209907, Bug #33197276)

    MySQL 8.0.29
    The derived materialized table condition pushdown optimization can now be used with most unions. This means that an outer WHERE condition can now be pushed down to every query block of the query expression of the materialized derived table or view.
    …
    This can now be done for most UNION queries. For exceptions, and additional information, see Derived Condition Pushdown Optimization. (Bug #24012, Bug #36802, Bug #106006, Bug #11746156, Bug #11748590, Bug #13650627, Bug #30587347, Bug #33318096, Bug #33738597, WL #13730)

到此,可以初步判定,这个 Bug 是由 MySQL 8.0.22 新引入的变量 derived_condition_pushdown 及其相关代码逻辑处理不恰引起的。

解决办法

找到原因,解决起来就很简单了。

  • (workaround) 参数 derived_condition_pushdown 默认值为 ON,修改全局变量将其改为 OFF,并将其进行持久化设定。
SET GLOBAL optimizer_switch='...,derived_condition_pushdown=off';
SET PERSIST optimizer_switch='...,derived_condition_pushdown=off';
  • 跳过问题版本,升级到更高版本,如 MySQL 8.0.33 或 MySQL 8.0.34。

Ps.

在查阅资料过程中,发现在新版本还有关于 derived_condition_pushdown 的 Bug,比如 Bug#109699 , Bug#110228 影响到 MySQL 8.0.32,在 MySQL 8.0.33 得到修复。看来这还是个有故事的 feature。

总结

在修复一个 Bug 时,可能引入新的 Bug,所以功能测试、版本适配很重要。 DBA 需要有不同版本、不同架构,甚至不同类型数据库的测试环境,用来测试或验证各种概念、问题。 没想到一个新特性影响了那么多版本,希望 MySQL 8.1 之后会带来不一样的感受~ 如果真要遇到什么问题不用慌,来墨天轮数说吐吐槽~

标签:8.0,再遇,derived,MySQL,pushdown,Bug,condition
From: https://blog.51cto.com/shawnyan/7268121

相关文章

  • 汇编调试命令debug的基本用法
      在学习16位汇编时,debug是常用的调试工具,但很多基本用法命令帮助中并未提及,经查验和实验,特记录如下:  一、基本概念:  1、参数分隔符  debug中参数之间的分隔符可用“空格”或“逗号”,效果一致,如:  -rax等于-r,ax  -d0100:00000010等于-d0100:0000,0010  2......
  • QT连接MySql关于驱动问题
    今天分享一下在qt中连接数据库遇到的一些问题,主要是mysql驱动以及mysql动态库加载1.环境变量配置一下mysql和QT的环境变量,这个比较简单,各位自行百度。2.编译mysql驱动用QT打开mysql.pro文件,在第六行首加上#,然后在末尾加入:win32:LIBS+=-LD:/MySql/mysql-8.1.0-winx64/lib-l......
  • 数据库MySQL
     Concat(a,b)连接a,b两个字段                                    MySQL函数       分组之后再插入查询条件不能用Where关键字,而要用HA......
  • MySQL 分析查询与来源机器
    当前分析针对版本:MariaDB10.5线上出现报错:can'tcreatemorethanmax_prepared_stmt_countstatements。造成这个错误的直接原因就是同时开启了prepare句柄太多导致的,所以比较直接的方式是调大参数,首先查看设置的值:showglobalvariableslike'max_prepared_stmt_count';......
  • Arch中使用Qt6的QtSql出现mysql driver not loaded的解决记录
    查阅了网上的说法,出现这个错误的原因大致可能有以下几种:Qt和mysql的位数不一样,一个是32位的,一个是64位的Qt中自带的驱动库与所使用的版本不匹配代码写错了,比如"QMYSQL"写成了"MYSQL"我出现个问题的原因是第二种。参考了一位老哥的博客QTMacM1解决mysqldrivernotloade......
  • MySQL的连接和导出数据分析和lift曲线
    MySQL的连接和使用https://www.cnblogs.com/zdstudy/p/16567399.htmlmysql使用网址https://blog.csdn.net/LikiLyn/article/details/120385981多个文件mergeimportpandasaspdimportnumpyasnpimportpymysql#%%打开数据库连接conn=pymysql.connect(host='地址',user......
  • UE4.27, Debug issues, "变量已被优化掉,因而不可用"
    调试时添加监控后,变量未被成功监控,显示"变量已被优化掉,因而不可用" 所使用的解决办法从解决方案配置的下拉菜单中选择DebugGameEditor  感谢阅读,敬请斧正......
  • mysql日志追踪 / 数据恢复
    1.查看日志开启状态showvariableslike'log_%';2.查看日志文件列表showbinarylogs;或者showmasterlogs;3.查看当前日志index位置showmasterstatus;4.查看binlog关键事件showbinlogevents[IN'log_name'][FROMpos][LIMIT[offset,]row_c......
  • MySQL online DDl原理
    onlineDDL从5.6开始,不阻塞DML但是会阻塞所有的DDL,online有三种模式:INSTANT(8.0.12),INPLACE(rebuild),INPLACE(no-rebuild),具体操作如下:1、只修改表的元数据信息删除二级索引修改索引名(5.7)修改字段名设置(删除)字段的默认值增加varchar长度,如果表示字符串长度的字节数变化则会使用c......
  • 《MySQL命令行客户端》的使用方法
    MySQL客户端连接工具有多种,但最常用的是MySQL命令行客户端。下面是MySQL命令行客户端的语法:mysql-hhostname-uusername-ppassword-Ddatabase_name其中:-h 参数指定要连接的MySQL服务器的主机名或IP地址。-u 参数指定要连接的MySQL服务器的用户名。-p 参数提示输......