mysql的临时表空间_Mysql临时表空间详解

一、临时表空间介绍

1、官方文档

Non-compressed, user-created temporary tables and on-disk internal temporary tables are created in a shared temporary tablespace

The innodb_temp_data_file_path configuration option defines the relative path, name, size, and attributes for temporary tablespace data files. If no value is specified for innodb_temp_data_file_path, the default behavior is to create an auto-extending data file named ibtmp1 in the innodb_data_home_dir directory that is slightly larger than 12MB.

Compressed temporary tables, which are temporary tables created using the ROW_FORMAT=COMPRESSED attribute, are created in file-per-table tablespaces in the temporary file directory.

The temporary tablespace is removed on normal shutdown or on an aborted initialization, and is recreated each time the server is started . The temporary tablespace receives a dynamically generated space ID when it is created. Startup is refused if the temporary tablespace cannot be created. The temporary tablespace is not removed if the server halts unexpectedly. In this case, a database administrator can remove the temporary tablespace manually or restart the server, which removes and recreates the temporary tablespace automatically.

2、翻译

用户创建的非压缩临时表和磁盘上的内部临时表是在共享临时表空间中创建的。

innodb_temp_data_file_path配置选项定义临时表空间数据文件的相对路径、名称、大小和属性。如果没有为innodb_temp_data_file_path指定值,默认行为是在innodb_data_home_dir目录中创建一个名为ibtmp1的自动扩展数据文件,该文件略大于12MB。

压缩临时表是使用ROW_FORMAT = COMPRESSED属性创建的临时表,它们是在临时文件目录中的每表文件表空间中创建的。

用户创建的临时表和磁盘内部临时表创建于共享临时表空间中。

innodb_temp_data_file_path配置选项定义临时表空间数据文件的相对路径,名称,大小和属性。 如果没有为innodb_temp_data_file_path指定值,则默认行为是在innodb_data_home_dir目录中创建一个稍大于12MB的名为 ibtmp1 的自动扩展数据文件。

临时表空间在正常关闭或中止初始化时被删除,并在每次启动服务器时重新创建 。 临时表空间在创建时会收到动态生成的空间ID。 如果无法创建临时表空间,则拒绝启动。 如果服务器意外停止,则不会删除临时表空间。 在这种情况下,数据库管理员可以手动删除临时表空间或重新启动服务器,从而自动删除并重新创建临时表空间。

3、解释

MySQL 5.7对于InnoDB存储引擎的临时表空间做了优化。在MySQL 5.7之前,INNODB引擎的临时表都保存在ibdata里面,而ibdata的贪婪式磁盘占用导致临时表的创建与删除对其他正常表产生非常大的性能影响。在MySQL5.7中,对于临时表做了下面两个重要方面的优化:

MySQL 5.7 把临时表的数据以及回滚信息(仅限于未压缩表)从共享表空间里面剥离出来,形成自己单独的表空间,参数为innodb_temp_data_file_path。

二、临时表与临时文件

1、临时表

临时表可以分为磁盘临时表和内存临时表,而临时文件,只会存在于磁盘上,不会存在于内存中。具体来说,临时表的内存形态有Memory引擎和Temptable引擎,主要区别是对字符类型(varchar, blob,text类型)的存储方式,前者不管实际字符多少,都是用定长的空间存储,后者会用变长的空间存储,这样提高了内存中的存储效率,有更多的数据可以放在内存中处理而不是转换成磁盘临时表。Memory引擎从早期的5.6就可以使用,Temptable是8.0引入的新的引擎。另外一方面,磁盘临时表也有三种形态,一种是MyISAM表,一种是InnoDB临时表,另外一种是Temptable的文件map表。其中最后一种方式,是8.0提供的。

在5.6以及以前的版本,磁盘临时表都是放在数据库配置的临时目录,磁盘临时表的undolog都是与普通表的undo放在一起(注意由于磁盘临时表在数据库重启后就被删除了,不需要redolog通过奔溃恢复来保证事务的完整性,所以不需要写redolog,但是undolog还是需要的,因为需要支持回滚)。

在MySQL 5.7后,磁盘临时表的数据和undo都被独立出来,放在一个单独的表空间ibtmp1里面。之所以把临时表独立出来,主要是为了减少创建删除表时维护元数据的开销。

在MySQL 8.0后,磁盘临时表的数据单独放在Session临时表空间池(#innodb_temp目录下的ibt文件)里面,临时表的undo放在global的表空间ibtmp1里面。另外一个大的改进是,8.0的磁盘临时表数据占用的空间在连接断开后,就能释放给操作系统,而5.7的版本中需要重启才能释放。

目前有以下两种情况会用到临时表:

1)用户显式创建临时表

这种是用户通过显式的执行命令create temporary table创建的表,引擎的类型要么显式指定,要么使用默认配置的值(default_tmp_storage_engine)。内存使用就遵循指定引擎的内存管理方式,比如InnoDB的表会先缓存在Buffer Pool中,然后通过刷脏线程写回磁盘文件。

在5.6中,磁盘临时表位于tmpdir下,文件名类似#sql4d2b_8_0.ibd,其中#sql是固定的前缀,4d2b是进程号的十六进制表示,8是MySQL线程号的十六进制表示(show processlist中的id),0是每个连接从0开始的递增值,ibd是innodb的磁盘临时表(通过参数default_tmp_storage_engine控制)。在5.6中,磁盘临时表创建好后,对应的frm以及引擎文件就在tmpdir下创建完毕,可以通过文件系统ls命令查看到。在连接关闭后,相应文件自动删除。因此,我们如果在5.6的tmpdir里面看到很多类似格式文件名,可以通过文件名来判断是哪个进程,哪个连接使用的临时表,这个技巧在排查tmpdir目录占用过多空间的问题时,尤其适用。用户显式创建的这种临时表,在连接释放的时候,会自动释放并把空间释放回操作系统。临时表的undolog存在undo表空间中,与普通表的undo放在一起。有了undo回滚段,用户创建的这种临时表也能支持回滚了。

在5.7中,临时磁盘表位于ibtmp文件中,ibtmp文件位置及大小控制方式由参数innodb_temp_data_file_path控制。显式创建的表的数据和undo都在ibtmp里面。用户连接断开后,临时表会释放,但是仅仅是在ibtmp文件里面标记一下,空间是不会释放回操作系统的。如果要释放空间,需要重启数据库。另外,需要注意的一点是,5.6可以在tmpdir下直接看到创建的文件,但是5.7是创建在ibtmp这个表空间里面,因此是看不到具体的表文件的。如果需要查看,则需要查看INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO这个表,里面有一列name,这里可以看到表名。命名规格与5.6的类似,因此也可以快速找到占用空间大的连接。

在8.0中,临时表的数据和undo被进一步分开,数据是存放在ibt文件中(由参数innodb_temp_tablespaces_dir控制),undo依然存放在ibtmp文件中(依然由参数innodb_temp_data_file_path控制)。存放ibt文件的叫做Session临时表空间,存放undo的ibtmp叫做Global临时表空间。这里介绍一下这个存放数据的Session临时表空间。Session临时表空间,在磁盘上的表现是一组以ibt文件组成的文件池。启动的时候,数据库会在配置的目录下重新创建,关闭数据库的时候删除。启动的时候,默认会创建10个ibt文件,每个连接最多使用两个,一个给用户创建的临时表用,另外一个给下文描述的优化器创建的隐式临时表使用。当然只有在需要临时表的时候,才会创建,如果不需要,则不会占用ibt文件。当10个ibt都被使用完后,数据库会继续创建,最多创建四十万个。当连接释放时候,会自动把这个连接使用的ibt文件给释放,同时回收空间。如果要回收Global临时表空间,依然需要重启。但是由于已经把存放数据的文件分离出来,且其支持动态回收(即连接断开即释放空间),所以5.7上困扰大家多时的空间占用问题,已经得到了很好的缓解。当然,还是有优化空间的,例如,空间需要在连接断开后,才能释放,而理论上,很多空间在某些SQL(如用户drop了某个显式创建的临时表)执行后,即可以释放。另外,如果需要查看表名,依然查看INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO这个表。需要注意的是,8.0上,显式临时表不能是压缩表,而5.6和5.7可以。

2)优化器隐式创建临时表

这种临时表,是数据库为了辅助某些复杂SQL的执行而创建的辅助表,是否需要临时表,一般都是由优化器决定。与用户显式创建的临时表直接创建磁盘文件不同,如果需要优化器觉得SQL需要临时表辅助,会先使用内存临时表,如果超过配置的内存(min(tmp_table_size, max_heap_table_siz)),就会转化成磁盘临时表,这种磁盘临时表就类似用户显式创建的,引擎类型通过参数internal_tmp_disk_storage_engine控制。一般稍微复杂一点的查询,包括且不限于order by, group by, distinct等,都会用到这种隐式创建的临时表。用户可以通过explain命令,在Extra列中,看是否有Using temporary这样的字样,如果有,就肯定要用临时表。

在5.6中,隐式临时表依然在tmpdir下,在复杂SQL执行的过程中,就能看到这临时表,一旦执行结束,就被删除。值得注意的是,5.6中,这种隐式创建的临时表,只能用MyISAM引擎,即没有internal_tmp_disk_storage_engine这个参数可以控制。所以,当我们的系统中只有innodb表时,也会看到MyISAM的某些指标在变动,这种情况下,一般都是隐式临时表的原因。

在5.7中,隐式临时表是创建在ibtmp文件中的,SQL结束后,会标记删除,但是空间依然不会返还给操作系统,如果需要返还,则需要重启数据库。另外,5.7支持参数internal_tmp_disk_storage_engine,用户可以选择InnoDB或者MYISAM表作为磁盘临时表。

在8.0中,隐式临时表是创建在Session临时表空间中的,即与用户显式创建的临时表的数据放在一起。如果一个连接第一次需要隐式临时表,那么数据库会从ibt文件构成的池子中取出一个给这个连接使用,直到连接释放。上文中,我们也提到过,在8.0中,用户显式创建的临时表也会从池子中分配一个ibt来使用,每个连接最多使用两个ibt文件用来存储临时表。我们可以查询INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES来确定ibt文件的去向。这个表中,每个ibt文件是一行,当前系统中有几个ibt文件就有几行。有一列叫做ID,如果此列为0,表示此ibt没有被使用,如果非0,表示被此ID的连接在用,比如ID为8,则表示process_id为8的连接在用这个ibt文件。另外,还有一列purpose,值为INTRINSIC表示是隐式临时表在用这个ibt,USER则表示是显示临时表在用。此外,还有一列size,表示当前的大小。用户可以查询这个表来确定整个数据库临时表的使用情况,十分方便。

在5.6和5.7中,内存临时表只能使用Memory引擎,到了8.0,多了一种Temptable引擎的选择。Temptable在存储格式有采用了变长存储,可以节省存储空间,进一步提高内存使用率,减少转换成磁盘临时表的次数。如果设置的磁盘临时表是InnoDB或者MYISAM,则需要一个转换拷贝的消耗。为了尽可能减少消耗,Temptable提出了一种overflow机制,即如果内存临时表超过配置大小,则使用磁盘空间map的方式,即打开一个文件,然后删除,留一个句柄进行读写操作。读写文件格式和内存中格式一样,这样就略过了转换这一步,进一步提高性能。注意,这个功能是在还没发布的8.0.16版本中才有的,因为还看不到代码,只能通过文档猜测其实现。在8.0.16中,参数internal_tmp_disk_storage_engine已经被去掉,磁盘临时表只能使用InnoDB形式或者TempTable的这种overflow形式。从文档中,我们似乎看出官方比较推荐使用TempTable这个新的引擎。具体性能提升情况,还需要等代码发布后,测试过才能得出结论。

2)临时文件

相比临时表,临时文件对大家可能更加陌生,临时文件更多的被使用在缓存数据,排序数据的场景中。一般情况下,被缓存或者排序的数据,首先放在内存中,如果内存放不下,才会使用磁盘临时文件的方式。临时文件的使用方式与一般的表也不太一样,一般的表创建完后,就开始读写数据,使用完后,才把文件删除,但是临时文件的使用方式不一样,在创建完后(使用mkstemp系统函数),马上调用unlink删除文件,但是不close文件,后续使用原来的句柄操作文件。这样的好处是,当进程异常crash,不会有临时文件因为没被删除而残留,但是坏处也是明显的,我们在文件系统上使用ls命令就看不到这个文件,需要使用lsof +L1来查看这种deleted属性的文件。

目前,我们主要在一下场景使用临时文件:

1)DDL中的临时文件

在做online DDL的过程中,很多操作需要对原表进行重建,对表重建前,需要对各种二级索引排序,而大量数据的排序,不太可能在内存中完成,需要依赖外部排序算法,MySQL使用了归并排序。这个过程中就需要创建临时文件。一般需要的空间大小与原表差不多。但是在使用完之后,会马上清理,所以在做DDL的时候,需要保留出足够的空间。用户可以通过指定innodb_tmpdir来指定这种排序文件的路径。这个参数可以动态修改,一般把他设置在有足够磁盘空间的路径上。临时文件的名字一般是类似ibXXXXXX,其中ib是固定前缀,XXXXXX是大小写字母以及数字的随机组合。

在做online DDL中,我们是允许用户对原表做DML操作的,即增删改查。我们不能直接插入原表中,因此需要一个地方记录对原表的修改操作,在DDL结束后,再应用在新表上。这个记录的地方就是online log,当然如果改动少的话,直接存在内存里(参数innodb_sort_buffer_size可控制,同时这个参数也控制online log每个读写块的大小)面即可。这个onlinelog也是用临时文件存,创建在innodb_tmpdir,最大大小为参数innodb_online_alter_log_max_size控制,如果超过这个大小了,DDL就会失败。临时文件的名字也类似上述的排序临时文件的名字。

在online DDL的最后阶段,需要把排序完的文件和中途产生的DML全都应用到一个中间文件上,中间文件文件名类似#sql-ib53-522550444.ibd,其中#sql-ib是固定的前缀,53是InnoDB层的table id,522550444是随机生成的数字。同时,在server层也会生成一个frm文件(8.0中没有),文件名类似#sql-4d2b_2a.frm,其中#sql是固定前缀,4d2b是进程号的十六进制表示,2a是线程号的十六进制表示(show processlist中的id)。因此我们也可以通过这个命名规则来找到哪个线程在做DDL。这里需要注意一点,这里说的中间文件,其实算是一个临时表,并不是上文说中临时文件,这些中间文件可以通过ls来查看。当在DDL中的最后一步,会把这两个临时文件命名回原来的表名。正因为这个特性,所以当数据库中途crash的时候,可能会在磁盘上留下残余无用的文件。遇到这种情况,可以先把frm文件重命名成与ibd文件一样的名字,然后使用DROP TABLE#mysql50##sql-ib53-522550444`来清理残余的文件。注意,如果不用drop命令,直接删除ibd文件,可能会导致数据字典里面依然有残余的信息,做法不太优雅。当然,在8.0中,由于使用了原子的数据字典,就不会出现这种残余文件了。

2)BinLog中的缓存操作

BinLog只有在事务提交的时候才会写入到文件中,在没提交前,会先放在内存中(由参数binlog_cache_size控制),如果内存放慢了,就会创建临时文件,使用方法也是先通过mkstemp创建,然后直接unlink,留一个句柄读写。临时文件名类似MLXXXXXX,其中ML是固定前缀,XXXXXX是大小写字母以及数字的随机组合。单个事务的BinLog太大,可能会导致整个BinLog的大小也过大,从而影响同步,因此我们需要尽可能控制事务大小。

3)优化创建的临时文件

有些操作,除了在引擎层需要依赖隐式临时表来辅助复杂SQL的计算,在Server层,也会创建临时文件来辅助,比如order by操作,会调用filesort函数。这个函数也会先使用内存(sort_buffer_size)排序,如果不够,就会创建一个临时文件,辅助排序。文件名类似MYXXXXXX,其中MY是固定前缀,XXXXXX是大小写字母以及数字的随机组合。

4)Load data中用的临时文件

在BinLog复制中,如果在主库上使用了Load Data命令,即从文件中导数据,数据库会把整个文件写入到RelayLog中,然后传到备库,备库解析RelayLog,从中抽取出对应的Load文件,然后在备库上应用。备库上这个文件存储的位置由参数slave_load_tmpdir控制。文档中建议这个目录不要配置在物理机的内存目录或者重启后会删除的目录。因为复制依赖这个文件,如果意外被删除,会导致复制中断。

5)其他

除了上文所述的几个地方外,还有其他几个地方也会用到临时文件:

在InnoDB层,启动的时候会创建多个临时文件用来存储:最后一次外键或者唯一键错误; 最后一次死锁的信息; 最后的innodb状态信息。用临时文件而不用内存的原因猜测是,内存使用率不会因为写这些指标而波动。

在Server层,分区表使用show create table时,会用到临时文件。另外在MYISAM表内部排序的时候也会用到临时文件。

三、行数据格式

b773d1262866

row_format.png

MySQL的文件格式在5.7之前是只有Antelope(羚羊)一种,在5.7之后新加了一种文件格式Barracuda(梭子鱼)。

所以MySQL的InnoDB引擎有两种文件格式:Antelope和Barracuda。

InnoDB早期的文件格式(页格式)为Antelope,可以定义两种行记录格式,分别是Compact和Redundant

Named File Format为了解决不同版本下页结构的兼容性,在Barracuda可以定义两种新的行记录格式Compressed和Dynamic

变量为innodb_file_format和innodb_default_row_format

mysql> SHOW VARIABLES LIKE 'innodb_file_format';

+--------------------+-----------+

| Variable_name | Value |

+--------------------+-----------+

| innodb_file_format | Barracuda |

+--------------------+-----------+

1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE '%row%format%';

+---------------------------+---------+

| Variable_name | Value |

+---------------------------+---------+

| innodb_default_row_format | dynamic |

+---------------------------+---------+

1 row in set (0.38 sec)

复制代码

四、参考资料

作者:无尘老施

链接:https://juejin.im/post/5f09a2fdf265da22ff54524e

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值