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

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 问题描述 表结构如下所示: 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解读
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
SQL 算法 搜索推荐
mysql 之order by工作流程
本文深入解析了MySQL中`ORDER BY`的排序机制,通过具体示例展示了排序过程及性能优化方法。文章首先分析了基于内存和磁盘的排序方式,包括`sort_buffer_size`的影响以及临时文件的使用场景。接着介绍了`rowid`排序算法,该算法通过减少参与排序的数据量来提升性能,并对比了其与传统排序的区别。此外,还探讨了随机查询`ORDER BY RAND()`的执行流程及其优化策略。最后提到了MySQL 5.6引入的优先队列排序算法,适用于仅需部分有序结果的场景。文章结合`optimizer_trace`工具详细说明了各配置参数对排序行为的影响,为优化查询提供了实用指导。
mysql 之order by工作流程
|
4月前
|
监控 关系型数据库 MySQL
|
2月前
|
SQL Oracle 关系型数据库
【YashanDB知识库】如何将mysql含有group by的SQL转换成崖山支持的SQL
本文探讨了在YashanDB(崖山数据库)中执行某些SQL语句时出现的报错问题,对比了MySQL的成功执行结果。问题源于SQL-92标准对非聚合列的严格限制,要求这些列必须出现在GROUP BY子句中,而SQL:1999及更高版本允许非聚合列直接出现在选择列中。YashanDB和Oracle遵循SQL-92标准,因此会报错。文章提供了两种解决方法:使用聚合函数处理非聚合列,或将GROUP BY与ORDER BY拆分为两层查询。最后总结指出,SQL-92标准更为严谨合理,建议开发者遵循此规范以避免潜在问题。
|
3月前
|
SQL Oracle 关系型数据库
【YashanDB 知识库】如何将 mysql 含有 group by 的 SQL 转换成崖山支持的 SQL
在崖山数据库中执行某些 SQL 语句时出现报错(YAS-04316 not a single-group group function),而这些语句在 MySQL 中能成功执行。原因是崖山遵循 SQL-92 标准,不允许选择列表中包含未在 GROUP BY 子句中指定的非聚合列,而 MySQL 默认允许这种操作。解决办法包括:使用聚合函数处理非聚合列或拆分查询为两层,先进行 GROUP BY 再排序。总结来说,SQL-92 更严格,确保数据一致性,MySQL 在 5.7 及以上版本也默认遵循此标准。
|
6月前
|
关系型数据库 MySQL 索引
MySQL的group by与count(), *字段使用问题
正确使用 `GROUP BY`和 `COUNT()`函数是进行数据聚合查询的基础。通过理解它们的用法和常见问题,可以有效避免查询错误和性能问题。无论是在单列分组、多列分组还是结合其他聚合函数的场景中,掌握这些技巧和注意事项都能大大提升数据查询和分析的效率。
602 0
|
7月前
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
本文详细解析了MySQL中`ORDER BY`的实现原理及优化方法。通过解析与优化、执行及多种优化技术,如索引利用、内存排序、外部排序等,帮助你提升排序性能。了解其背后的机制,可显著优化查询效率。
450 4
|
7月前
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
在实际开发中,我们经常会使用 MySQL 的 `ORDER BY`进行排序,那么,`ORDER BY`是如何实现的排序的?我们该如何优化 `ORDER BY`的排序性能?这篇文章,我们来聊一聊。
92 3
|
8月前
|
关系型数据库 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’
439 0
|
9月前
|
关系型数据库 MySQL 数据处理
Mysql关于同时使用Group by和Order by问题
总的来说,`GROUP BY`和 `ORDER BY`的合理使用和优化,可以在满足数据处理需求的同时,保证查询的性能。在实际应用中,应根据数据的特性和查询需求,合理设计索引和查询结构,以实现高效的数据处理。
980 1
|
9月前
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 `GROUP BY` 子句
【8月更文挑战第12天】
334 1

相关产品

  • 云数据库 RDS MySQL 版