前言

如果您使用MySQL数据库,可能会遇到“The table XXX is full”错误。这是由于MySQL无法将新行插入表中,因为该表已达到其最大大小限制所致。这个错误通常是由于磁盘空间不足或由于表上的临时表所引起的。在本文中,我们将为您介绍如何诊断这个错误,找到原因并提供解决方案。

问题

近日公司一个程序在使用MySQL过程中,出现了The table '/tmp/#sql1_34519d_0' is full的错误,后续导致数据库OOM,最后数据库自动重启。

时间轴:

  • 5:00~7:30报以下错误:

image-20220214090140015

  • 8:00报以下错误:

image-20220214090155271

9:40分数据库自动重启。

排查过程

  1. 起初运维及研发都下意识认为The table XXX is full是磁盘或内存问题导致的,大部分的处理方法均是清理磁盘空间后解决,但运维告知磁盘还有100多G空间,并且内存使用情况也都是正常的。故暂时认为不是该问题导致。

    img

    img

  2. 后面研发认为可能是数据库查询数量太多,导致了数据库缓存不足,但同事告知该时段程序的SQL应该是查询不出任何数据的。故暂时认为不是该问题导致。

  3. 后面经过搜索,在percona论坛的一篇帖子中找到了相同的问题

    image-20220214091345073

    其大致描述的是用户使用MySQL8.0.22-13 to 8.0.23-14时,有一个复杂查询(使用 UNION, GROUP BY, ORDER BY 和很多 JOINs)出现了查询失败,MySQL报错:(HY000/1114): The table '/tmp/#sql1_f519f_7' is full,该用户查询了磁盘存储还有481Gb可用。

    PS:公司使用的数据库版本是MySQL-8.0.16

    • 帖子解决方案:

    image-20220214091508282

    大致意思是MySQL8的新缓存引擎TempTable在早期版本中有一些Bugs和问题,所以建议将缓存引擎修改为TempTable,修改方式如下:

    set global internal_tmp_mem_storage_engine=Memory;
    
    • TempTable

      MySQL 8.0 开始,专门实现了一个临时表的引擎 TempTable , 解决了 VARCHAR字段的边长存储以及大对象的内存存储。由变量 interal_tmp_mem_storage_engine来控制,可选值为 TempTable(默认)和 Memory;新引擎的大小由参数temp_table_max_ram 来控制,默认为1G。超过了则存储在磁盘上(ibtmp1)。并且计数器由性能字典的表 memory_summary_global_by_event_name 来存储。

    此Bug官方在8.0.27中宣布修复:

    fixed as of the upcoming 8.0.27 release:

    A query that used a temporary table for aggregation exhausted the memory available to the TempTable storage engine, causing an update operation to fail with a table is full error. (Bug #31117893, Bug #99100)

解决方案

有两种解决方案:

  1. 升级MySQL版本至8.0.27及以上
  2. 修改internal_tmp_mem_storage_engineMemory

其他

  • MySQL官方Bugs【#99100】有关于TempTableBug的详细用户QA记录,有兴趣的读者可以看看。

  • 早期的TempTable引擎性能比Memory弱,具体可查阅MySQL官方Bugs【#98782】

  • 不同环境出现此Bug的情形不尽相同,请做好充分验证测试再调整生产环境配置。

参考文档

  1. GROUP BY will throw table is full when temptable memory allocation exceed limit
  2. Using TempTable engine for GROUP BY is slower than using MEMORY engine