首页 > 数据库 > 数据库开发技术 > 从MySQL的ibtmp1文件太大说起
ll -h ibtmp1-rw-r----- 1 mysql mysql 192G Aug 12 16:20 ibtmp1
# 设置innodb_fast_shutdown参数
SET GLOBAL innodb_fast_shutdown = 0; # 此步骤可以省略# 关闭数据库实例shutdown; # 因本实例为MySQL5.7 可以直接在SQL命令行中shutdown关闭
innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5G # 12M代表文件初始大小,5G代表最大sizemysql> show variables like 'innodb_temp_data_file_path';+----------------------------+-------------------------------+| Variable_name | Value |+----------------------------+-------------------------------+| innodb_temp_data_file_path | ibtmp1:12M:autoextend:max:5G |+----------------------------+-------------------------------+1 row in set (0.01 sec)
/** 先看一下表结构 */mysql> show create table test_tmp1\G*************************** 1. row ***************************Table: test_tmp1Create Table: CREATE TABLE `test_tmp1` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`col2` varchar(25) DEFAULT NULL,PRIMARY KEY (`id`),KEY `name` (`name`)) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf81 row in set (0.00 sec)/** group by无索引字段*/mysql> explain select * from test_tmp1 group by col2 ;+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+| 1 | SIMPLE | test_tmp1 | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 100.00 | Using temporary; Using filesort |+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+/** group by 与order by字段不一致时,及时group by和order by字段有索引也会使用 */mysql> explain select name from test_tmp1 group by name order by id desc;+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------------------------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------------------------------------+| 1 | SIMPLE | test_tmp1 | NULL | range | name | name | 153 | NULL | 3 | 100.00 | Using index for group-by; Using temporary; Using filesort |+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------------------------------------+1 row in set, 1 warning (0.02 sec)
/** 例子中有无索引时会存在,如果2个字段都有索引会如何*/mysql> alter table test_tmp1 add key col2(col2);Query OK, 0 rows affected (1.07 sec)Records: 0 Duplicates: 0 Warnings: 0/** 结果如下,其实该写法与group by +order by 一样*/mysql> explain select distinct col2 from test_tmp1 order by name;+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+---------------------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+---------------------------------+| 1 | SIMPLE | test_tmp1 | NULL | index | col2 | col2 | 78 | NULL | 8 | 100.00 | Using temporary; Using filesort |+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+---------------------------------+1 row in set, 1 warning (0.00 sec)
/** 先测一下union all的情况*/mysql> explain select name from test_tmp1 union all select name from test_tmp1 where id <10;+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+| 1 | PRIMARY | test_tmp1 | NULL | index | NULL | name | 153 | NULL | 8 | 100.00 | Using index || 2 | UNION | test_tmp1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 8 | 100.00 | Using where |+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+2 rows in set, 1 warning (0.01 sec)/** 再看一下union 作为对比,发现出现了使用临时表的情况*/mysql> explain select name from test_tmp1 union select name from test_tmp1 where id <10;+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+| 1 | PRIMARY | test_tmp1 | NULL | index | NULL | name | 153 | NULL | 8 | 100.00 | Using index || 2 | UNION | test_tmp1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 8 | 100.00 | Using where || NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+3 rows in set, 1 warning (0.00 sec)
/** 简单看一下本表的数据重复插入的情况 */mysql> explain insert into test_tmp1(name,col2) select name,col2 from test_tmp1;+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-----------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-----------------+| 1 | INSERT | test_tmp1 | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | NULL || 1 | SIMPLE | test_tmp1 | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 100.00 | Using temporary |+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-----------------+2 rows in set (0.00 sec)
innodb_temp_data_file_pathtmp_table_sizemax_heap_table_sizedefault_tmp_storage_engineinternal_tmp_disk_storage_engine
tmp_table_size = 16Minnodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5G
/** 造一张表或者从其他表复制一批数据,为了方便模拟,可以不创建主键及索引*/mysql> create table test_tmp3 select * from db1.tbname;Query OK, 15948372 rows affected (2 min 27.24 sec)Records: 15948372 Duplicates: 0 Warnings: 0
ll -h ibtmp1-rw-r----- 1 mysql mysql 12M Aug 15 16:06 ibtmp1 /** 此时是默认的初始大小*/
/** 此方式将会使用临时表空间,且 tmp_table_size参数已调小为16M,本表当前有2G多,所以会使用临时表空间*/mysql> insert into test_tmp3 select * from test_tmp3 ;Query OK, 15948372 rows affected (2 min 7.40 sec)Records: 15948372 Duplicates: 0 Warnings: 0
ll -h ibtmp1-rw-r----- 1 mysql mysql 2.8G Aug 15 16:17 ibtmp1 /** 此时已使用了2.8G*/
ll -h bak_db/test_tmp3* /** 结果中已有5.8G*/-rw-r----- 1 mysql mysql 8.9K Aug 15 16:04 bak_db/test_tmp3.frm-rw-r----- 1 mysql mysql 5.8G Aug 15 16:16 bak_db/test_tmp3.ibd
/** 继续插入时 因临时表空间大小有限制,超过5G后将异常,信息如下*/mysql> insert into test_tmp3 select * from test_tmp3;ERROR 1114 (HY000): The table '/app/data/mysql3306/tmp/#sql_32469_0' is full
ll -h ibtmp1-rw-r----- 1 mysql mysql 5.0G Aug 15 16:17 ibtmp1 /** 此时已使用了5.0G,已达到上限*/
2019-08-15T08:23:47.016495Z 3 [ERROR] /usr/local/mysql5.7/bin/mysqld: The table '/app/data/mysql3306/tmp/#sql_32469_0' is full以上测试实例因不同的版本可能会有差异,建议大家亲自测试一下。

精彩推荐:
原文作者:数据库干货铺;如有侵权,请联系管理员删除。