MySQL · 捉虫动态 · left-join多表导致crash

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 有一天小编胡乱写SQL, left join了30张表, 结果导致了Mysql server gone away… 我们来看看crash堆栈 <signal handler called> base_list_iterator::next update_ref_and_keys make_

有一天小编胡乱写SQL, left join了30张表, 结果导致了Mysql server gone away…
我们来看看crash堆栈

<signal handler called>
base_list_iterator::next
update_ref_and_keys
make_join_statistics
JOIN::optimize
mysql_execute_select

可以看出, 在产生执行计划过程中crash了。

追查

堆栈表明, update_ref_and_keys函数中join_tab->join->join_list为无效地址。 排查看到函数入口处这个变量还是ok的, 那么在gdb里watch一下。

Hardware watchpoint 4: join_tab->join->join_list

Old value = (List<TABLE_LIST> *) 0x3431f60
New value = (List<TABLE_LIST> *) 0xc800000000000000

这么整齐的地址一看就有问题。函数栈:

Key_field::Key_field
add_key_field
add_key_equal_fields
add_key_fields
update_ref_and_keys

add_key_fields修改join_tab->join->join_list实际是不合理的, 因此这里说明一下路径上几个关键的函数。

原因分析

还要从子查询优化说起,当遇到semi-join子查询情况下, JOIN::optimize()会调用JOIN::flatten_subqueries改写SQL, 如下形式:

SELECT ...
FROM ot1, ...
WHERE oe IN (SELECT ie FROM it1, ..., itN WHERE subq_where)
		AND outer_where

会被修改为:

SELECT ...
FROM ot SEMI JOIN (it1, ... , itN),
WHERE outer_where AND subq_where AND oe=ie

函数JOIN::flatten_subqueries, 做了以下几件事:

  • 创建semi join(it1, …, itN)的节点并添加到外层查询语句的FROM语法树下
  • subq_where AND oe=ie加入到外层查询语句的WHERE树下
  • 再移除原先的子查询语句

JOIN::flatten_subqueries中, 对于每一个子查询, 调用函数JOIN::convert_subquery_to_semijoin, 那么子查询上维护的query信息也要同步加到外部查询上。所以可见, 子查询中的信息, 会转交给外部查询。

之后, JOIN::optimize()调用update_ref_and_keys, 这个函数用来处理出最终查询要使用的索引。crash的问题也出现在这个函数中, 因此还要看update_ref_and_keys内部做了什么。

在函数update_ref_and_keys中, 一个重要的数组, key_fields, 用来存放所有可能用到的索引字段。先通过key_fields=(Key_field*) thd->alloc(sz)分配空间, 再调用add_key_fields递归遍历WHERE树, 遇到等值表达式, 会填充到key_fields数组中。而之前已经看到, add_key_field在写key_fields时却修改了join_tab->join->join_list

// add_key_fields中修改了join_tab->join->join_list的代码
new (*key_fields)
    Key_field(field, *value, and_level, exists_optimize, eq_func,
              null_rejecting, NULL, get_semi_join_select_list_index(field));
    (*key_fields)++;

可见在new的时候拿到了join_tab->join->join_list, 是(*key_fields++)的时候, 加过头了。从而可推断, key_fields没有分配到应该有的内存空间。那么出问题的就是sz用来分配空间的数字了。

// sz的计算方法
sz= max(sizeof(Key_field), sizeof(SARGABLE_PARAM)) *
    (((select_lex->cond_count + 1) * 2 +
select_lex->between_count) * m + 1);

这里涉及到两个变量select_lex->cond_countselect_lex->between_count, 而cond_count就是number of conditions; 构造的语句中的等值表达式足有31条, 而这里在分配时是2, 活该内存越界。
而这个变量在子查询优化过程中, 子查询应该将其移交给外部查询语句。

修复

函数JOIN::convert_subquery_to_semijoin中, 改写完SQL后, 忘记把子查询的cond_count和between_cond信息更新到外部查询了, 这时只要手动添加即可。

官方修复(5.6.25)参见
相关worklog参见

复现

可以通过以下方式复现

create table t1 (
  `id` int(20),
  `col3` varchar(60) default null,
  primary key (id)
);

create view `v_test` as
select t1.col1 as col1,
      t2.col2 as col2,

      ...

      t30.col30 as col30
      from (((((((((((((((((((((((((((((t1
          left join t2 on (t1.id = t2.id))
          left join t3 on (t1.id = t3.id))

          ...

          left join t30 on (t1.id = t30.id));

然后执行

create table tt (id int(20), b varchar(200));
select * from tt where b in (select col1_1 fromom v_test);

MySQL5.6在5.6.25之前的小版本都可以复现, 请尽情调戏 .^.

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5月前
|
关系型数据库 MySQL
MYSQL-多表操作-外键约束
MYSQL-多表操作-外键约束
|
6月前
|
SQL druid Java
java mysql druid mybatis-plus里使用多表删除出错的一种处理方式
java mysql druid mybatis-plus里使用多表删除出错的一种处理方式
83 0
|
6月前
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
|
5月前
|
关系型数据库 MySQL 数据库
关系型数据库MySQL开发要点之多表设计案例详解代码实现
关系型数据库MySQL开发要点之多表设计案例详解代码实现
60 2
|
4月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何进行MySQL到MySQL的动态同步
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
关系型数据库 MySQL Serverless
实时计算 Flink版产品使用问题之使用cdas语法同步mysql数据到sr serverless是否支持动态加表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
Oracle 关系型数据库 MySQL
MYSQL-多表联合查询汇总
MYSQL-多表联合查询汇总
|
5月前
|
SQL 关系型数据库 MySQL
MySQL周内训参照3、简单查询与多表联合复杂查询
MySQL周内训参照3、简单查询与多表联合复杂查询
47 1
|
5月前
|
SQL 存储 关系型数据库
17. Mysql 动态SQL
17. Mysql 动态SQL
85 1
|
4月前
|
存储 关系型数据库 MySQL
MySQL数据库—多表设计与关联查询
MySQL数据库—多表设计与关联查询

相关产品

  • 云数据库 RDS MySQL 版