1.将源表select的结果放入一个临时表
可以通过show processlist来查看
mysql> show processlist;
+----+------+-----------+------+---------+------+------------------------------+------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------+---------+------+------------------------------+------------------------------------------+
| 1 | root | localhost | test | Query | 170 | Copying to tmp table on disk | insert into t1 select null, b, c from t1 |
| 2 | root | localhost | test | Query | 0 | NULL | show processlist |
+----+------+-----------+------+---------+------+------------------------------+------------------------------------------+
通过改变tmpdir参数(指定到一个可用空间更大的目录)解决这个问题。
现在来说两个问题:
1. 为什么创建的临时表类型是myisam呢?
因为临时表默认的类型是memory,但是临时表的大小有限制(由tmp_table_size和max_heap_table_size决定,默认两者是相等的),如果超过了这个值就自动转化为磁盘临时表,类型为myisam,所以也就有了我上面遇到的现象。
2. 每次生成的临时表的大小与源表是什么关系呢。比如我之前测试中t大小是1G,那么执行insert into t1 select null, b, c from t1; 这时去查看生成的临时表的大小是2G。
这个与源表的字段类型有关系,我大概测试了int, bigint, char,varchar这集中情况,结果如下:
bigint测试结果:
CREATE TABLE `t1` (
`a` bigint(20) DEFAULT NULL,
`b` bigint(20) DEFAULT NULL,
`c` bigint(20) DEFAULT NULL,
`d` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
源表大小
-rw-rw---- 1 repls repls 8.5K 1月 16 22:21 t1.frm
-rw-rw---- 1 repls repls 136M 1月 16 22:22 t1.ibd
insert into t1 select * from t1生成的临时表大小:
-rw-rw---- 1 repls repls 66M 1月 16 22:26 #sql_15da_0.MYD
-rw-rw---- 1 repls repls 1.0K 1月 16 22:26 #sql_15da_0.MYI
int 测试结果:
CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
源表大小
-rw-rw---- 1 repls repls 8.5K 1月 16 22:32 t2.frm
-rw-rw---- 1 repls repls 188M 1月 16 22:33 t2.ibd
insert into t2 select * from t2生成临时表的大小:
-rw-rw---- 1 repls repls 68M 1月 16 22:35 #sql_15da_0.MYD
-rw-rw---- 1 repls repls 1.0K 1月 16 22:35 #sql_15da_0.MYI
char类型测试结果:
CREATE TABLE `t3` (
`a` char(200) DEFAULT NULL,
`b` char(200) DEFAULT NULL,
`c` char(200) DEFAULT NULL,
`d` char(200) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
源表大小
-rw-rw---- 1 repls repls 8.5K 1月 16 22:38 t3.frm
-rw-rw---- 1 repls repls 240M 1月 16 22:41 t3.ibd
insert into t3 select * from t3生成临时表大小:
-rw-rw---- 1 repls repls 601M 1月 16 22:41 #sql_15da_0.MYD
-rw-rw---- 1 repls repls 1.0K 1月 16 22:41 #sql_15da_0.MYI
varchar测试结果:
CREATE TABLE `t4` (
`a` varchar(200) DEFAULT NULL,
`b` varchar(200) DEFAULT NULL,
`c` varchar(200) DEFAULT NULL,
`d` varchar(200) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
源表大小:
-rw-rw---- 1 repls repls 8.5K 1月 16 22:43 t4.frm
-rw-rw---- 1 repls repls 56M 1月 16 22:43 t4.ibd
insert into t4 select * from t4生成临时表大小:
-rw-rw---- 1 repls repls 1.2G 1月 16 22:45 #sql_15da_0.MYD
-rw-rw---- 1 repls repls 1.0K 1月 16 22:45 #sql_15da_0.MYI
从上面的几组数据来看,对于不同字段类型,他们转化成磁盘临时表后数据大小都不是预期的2倍关系(为什么预期是2倍关系,因为insert into select实质上是数据重复一遍,自然是2倍),这可能与innodb表和myisam表存储格式有关(磁盘临时表是myisam类型),具体原因有待进一步研究。但是我有一点我可以确定:源表是varchar类型的都会转为char类型存储因为memory类型的表没有varchar类型。
关于上面生成临时表的数据文件大小与源表的关系如果有哪位弄得很清楚了麻烦留个言,毕竟平常线上还是有很多这种需要生成临时表的操作,了解这个可以预期估计需要多少的磁盘空间,以免因为磁盘空间不够而导致操作失败。