MySQL中会话产生的临时表空间和磁盘空间的使用
2022-06-01 23:13 abce 阅读(751) 评论(0) 编辑 收藏 举报本文主要关注会话临时表空间,当查询需要存储比tmp_table_size还多的数据或 TempTable引擎分配的内存映射临时文件比temptable_max_mmap还多时,InnoDB基于磁盘的内部临时表就会发挥作用。
如果以上情况发生,则需要为执行查询的会话分配临时表空间池中的表空间。临时表空间池最初包含10个在启动实例时创建的临时表空间。池的大小永远不会缩小,如果需要,表空间会自动添加到池中。表空间(IBT 文件)的默认大小为 5个页或80KB。
当会话断开连接时,它的临时表空间将被truncate并以其初始大小释放到池中。truncate操作仅在会话断开时发生;这也意味着只要会话还在连接着,表空间就会消耗磁盘空间。 MySQL可以为将来的查询重用该区域,但如果一个查询需要大量临时空间,则IBT文件将在会话的整个生命周期内保持很大。
我们演示一下这种行为。
首先,我们创建一个表并插入一百万行记录。附带说明一下,将SHA1校验和(checksums)存储在char(40)字段中并不完美,但它使测试更清晰。
1 2 | # ls -la './#innodb_temp/temp_10.ibt' -rw-r ----- 1 mysql mysql 80K 05-29 14:10 temp_10.ibt |
然后,将执行以下使用临时表的查询。由于临时表大小大于 tmp_table_size 的值(默认为16MB),因此该查询将不得不使用会话临时表空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | mysql> pager pt-visual-explain mysql> explain SELECT * FROM ( SELECT * FROM table01 UNION SELECT * FROM table01 ORDER BY s DESC ) t LIMIT 1; Table scan rows 1991860 +- DERIVED table derived( temporary ( union (table01,table01))) +- Table scan +- TEMPORARY table temporary ( union (table01,table01)) +- Filesort +- Table scan +- UNION table union (table01,table01) +- Table scan | rows 995930 | +- Table | table table01 +- Table scan rows 995930 +- Table table table01 mysql> SELECT * FROM ( SELECT * FROM table01 UNION SELECT * FROM table01 ORDER BY s DESC ) t LIMIT 1; + --------+------------------------------------------+ | id | s | + --------+------------------------------------------+ | 999145 | fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f | + --------+------------------------------------------+ |
让我们在执行查询后检查附加到该会话的临时表空间:
1 2 3 4 5 6 7 8 9 | mysql> SELECT PATH, format_bytes( SIZE ), STATE, PURPOSE FROM INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES WHERE id = CONNECTION_ID(); + ----------------------------+--------------------+--------+-----------+ | PATH | format_bytes( SIZE ) | STATE | PURPOSE | + ----------------------------+--------------------+--------+-----------+ | ./#innodb_temp/temp_10.ibt | 392.00 MiB | ACTIVE | INTRINSIC | + ----------------------------+--------------------+--------+-----------+ # ls -la './#innodb_temp/temp_10.ibt' -rw-r ----- 1 mysql mysql 392M 05-29 14:10 temp_10.ibt |
关闭会话后,文件大小恢复为默认值:
1 2 | # ls -la './#innodb_temp/temp_10.ibt' -rw-r ----- 1 mysql mysql 80K 05-29 14:10 temp_10.ibt |
这个过程正如MySQL手册中的描述的那样,但是,这也意味着它可能会出现问题。长会话在数据库世界中并不少见,主要是在应用程序使用连接池的情况下。此外,连接池正是为此目的而设计的,以减轻每次应用程序需要时创建新连接的开销,因为重用与数据库的现有连接比打开新连接更有效。
例如,如果在应用程序和MySQL之间,使用ProxySQL作为中间件,则应用程序缺乏对后端连接的大部分控制。这意味着将使用与后端的负载均衡连接,而且连接很可能永远存在。由于这个事实,MySQL很少会从Session Temporary Tablespace中回收空间,因此,这会增加整体磁盘空间的利用。
这并不难出现。不时进行一次大负载的OLAP查询就足以产生滚雪球的效应了。
ProxySQL有一个强制后端连接重新初始化的选项——mysql-connection_max_age_ms(默认禁用)。但是,这只适用于ProxySQL,但是连接池有很多种,其中一些是直接在应用程序端实现的,这通常会增加整个问题的复杂性。
在理想情况下,MySQL应该通过更频繁地触发truncate过程来处理这个问题。已经有提交了相应的功能请求(https://bugs.mysql.com/bug.php?id=107372)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)