MySQL · 捉虫动态 · ORDER/GROUP BY 导致 mysqld crash

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 问题描述 表结构如下所示: show create table test\G Table: test Create Table: CREATE TABLE `test` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

问题描述

表结构如下所示:

show create table test\G
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id2` varchar(50) DEFAULT NULL
  `id3` varchar(100) DEFAULT NULL
  `some_text` varchar(200) DEFAULT NULL
  `name` varchar(20) DEFAULT NULL
  `another_text` varchar(500) DEFAULT NULL
  `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1024 DEFAULT CHARSET=utf8

对 mysql 执行如下语句:

select count(distinct(id2))
from santo_test
where id3 = 'hahaha'
group by substr(ctime, 0, 10)

会导致mysql crash(signal 11)。

崩溃堆栈如下:

pthread_kill ()
handle_segfault (sig=11)
 <signal handler called>
ptr_compare ()
queue_insert ()
merge_buffers()
merge_many_buff()
filesort()
create_sort_index()
JOIN::exec()
mysql_select()
handle_select()
execute_sqlcom_select()
mysql_execute_command()
mysql_parse()
...

官方bug传送

Bug复现小贴士
一条select语句搞挂MySQL Server? 当然还是需要苛刻条件的:

  • 需要保证 sort by/group by 的列本身是 CHAR(0) NOT NULL, 值也要多样化, 不然会直接在优化器被优化掉;
  • 接着该列不能有索引, 确保逻辑走到filesort(在对索引列做GROUP BY/ORDER BY时直接走索引);
  • 之后要配备足够小的sort_buffer_size, 和足够量大的数据撑满 sort_buffer,如@@sort_buffer_size = 32768时,40行数据就可以触发;
  • 然后默默的给 substr 函数投喂错误的参数。

BOOM!

搞完破坏, 我们来看问题怎么解。

成因解析

在看到触发 crash 语句的时候,一定有读者发现哪里不对了。这里使用的 substr(some_string, 0, some_length) 这样的写法,而官方文档中 substr 函数的 @param2 实际上是从1开始计算,当起始位置置为0的时候,这条语句返回值其实是空的。当然,最终导致压坏 mysql server 的一根稻草,正是这个长度为0的字符串。

现在我们沿着执行路线来探索 mysql 是如何一步步挂掉的,在 select 语句中使用 order by/group by 语句时,server 通常调用排序,主要通过索引或者 filesort 来实现排序,在 group by/order by 的列上不存在索引时,server 会选择使用 filesort,其主要逻辑见 filesort.cc:filesort()。这里还会涉及到一个变量,sort_buffer_size,当需要排序的数据量超过sort_buffer_size 大小时,server 会将数据划分为 trunks,这时调用 merge_many_buffers()。随后一路调用到 mysys/ptr_cmp.c 文件中的比较函数,这里的比较函数是按字节进行的,每四个字节为一个比较单位,当传入的参数长度小于4时,会调用 ptr_compare(),而在上节的调用栈可以看到,最后 crash 就是在这个函数里。函数槽点如下:

static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
{
  reg3 int length= *compare_length;
  reg1 uchar *first,*last;

  first= *a; last= *b;
  while ( --length)
  {
    if (*first++ != *last++)
      return (int) first[-1] - (int) last[-1];
  }
  return (int) first[0] - (int) last[0];
}

在 lengh == 0 时,while 里就会根本停不下来,直到被比较的两位指针不停自加到一个不能访问的内存区域,逼迫系统用 signal 11 杀死 mysql server。

解决方案

比较长度为0的字符串本身是个意外, 所以解决方案就是添加一个辅助函数 ptr_compare_length_zero,在 length 为0时直接返回0,在做排序函数分派时,将长度为0的比较指派到ptr_compare_length_zero
因此,想搞挂MySQL Server,这条路已经被堵上了,还是多修bug少搞破坏比较好 :-)

  1. 官方fix160c6920509516a1e05b855799479a59c27803191
  2. 官方fix2 b62c5daa646434290c9b2d1c9b162487cb8edf04
  3. MySQL · 社区动态 · MySQL5.6.26 ReleaseNote解读
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
关系型数据库 MySQL 数据库
docker启动mysql多实例连接报错Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’
docker启动mysql多实例连接报错Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’
214 0
|
4月前
|
关系型数据库 MySQL 数据处理
Mysql关于同时使用Group by和Order by问题
总的来说,`GROUP BY`和 `ORDER BY`的合理使用和优化,可以在满足数据处理需求的同时,保证查询的性能。在实际应用中,应根据数据的特性和查询需求,合理设计索引和查询结构,以实现高效的数据处理。
644 1
|
4月前
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 `GROUP BY` 子句
【8月更文挑战第12天】
109 1
|
5月前
|
关系型数据库 MySQL Linux
Docker安装mysql详细教程, mysqld: Can‘t read dir of ‘/etc/mysql/conf.d/‘(报错已解决)
Docker安装mysql详细教程, mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 2 - No such file or directory) 已解决
|
4月前
|
存储 关系型数据库 MySQL
MySQL中的DISTINCT与GROUP BY:效率之争与实战应用
【8月更文挑战第12天】在数据库查询优化中,DISTINCT和GROUP BY常常被用来去重或聚合数据,但它们在实现方式和性能表现上却各有千秋。本文将深入探讨两者在MySQL中的效率差异,结合工作学习中的实际案例,为您呈现一场技术干货分享。
511 0
|
6月前
|
JSON 关系型数据库 MySQL
MySQL中GROUP_CONCAT与JSON_OBJECT、GROUP BY的巧妙结合:打造高效JSON数组汇总
MySQL中GROUP_CONCAT与JSON_OBJECT、GROUP BY的巧妙结合:打造高效JSON数组汇总
186 1
|
5月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何进行MySQL到MySQL的动态同步
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
6月前
|
关系型数据库 MySQL Serverless
实时计算 Flink版产品使用问题之使用cdas语法同步mysql数据到sr serverless是否支持动态加表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
关系型数据库 MySQL Linux
Linux部署实战前言,MySQL在CentOS安装【单机软件】,MySQL的安装需要root权限,yum install mysql,systemctl enable mysqld开机自启的意思
Linux部署实战前言,MySQL在CentOS安装【单机软件】,MySQL的安装需要root权限,yum install mysql,systemctl enable mysqld开机自启的意思
|
6月前
|
关系型数据库 MySQL
mysql动态查列(case when then else end)
mysql动态查列(case when then else end)

相关产品

  • 云数据库 RDS MySQL 版