请不要被错误消息所迷惑The table 'my_table' is full
。这种罕见的情况与磁盘空间完全无关。该表的完整状态与InnoDB的内部管道有关。
首先,看一下这个InnoDB体系结构图
请注意,系统表空间(文件ibdata)仅具有128个回滚段和每个回滚段1023个回滚槽。这就限制了事务的回滚容量的大小。换句话说,如果单个回滚段需要超过1023个插槽来支持事务,则该事务将达到该table is full
条件。
想想新泽西州的Red Lobster餐厅。它可以容纳200人。如果餐厅满员,可能会有很多人在外面等。如果排队的人不耐烦,他们可能会因为餐厅已满而离开。显然,解决方案不是扩大新泽西州(或增加磁盘空间)。解决方案是使Red Lobster餐厅更大。这样,您可以将座位数增加到240个。即使这样,如果有240多人决定来Red Lobster,可能会在外面形成排队。
仅举一个例子,我有一个具有2TB系统表空间的客户端,并且禁用了innodb_file_per_table。(ibdata1为346G,ibdata2为复位)。我跑了这个查询
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
接下来,我从ibdata1和ibdata2的文件大小之和中减去了InnoDBDataIndexSpace。我有两件事震惊了我
- 系统表空间内剩余106GB。
- 我有同样的
Table is Full
情况
这意味着106GB用于InnoDB的内部管道。客户端当时正在使用ext3。
对我来说,解决方案是添加ibdata3。我在旧帖子中讨论了此问题,如何使用“ innodb_file_per_table”解决“表...已满”的问题?
我在其他帖子中也对此进行了讨论
请记住,即使启用了innodb_file_per_table,也会发生这种情况。怎么样?回滚和撤消日志是ibdata1增长的不受控制的峰值来源。
您的实际问题
由于您要向表中添加索引并获取Table is Full
,因此表必须很大并且不能容纳在单个回滚段中。您必须执行以下操作:
步骤01
将数据放入转储文件
mysqldump --no-create-info mydb mytable > table_data.sql
步骤02
登录到MySQL并运行它
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
步骤03
用数据的附加索引加载表
mysql -Dmydb < table_data.sql
就这样。
看到的问题是,ALTER TABLE将尝试将巨大表中的所有行作为单个事务注入。使用mysqldump会将数据一次插入数千行,而不是单个事务中的所有行插入到表中(现在有了新索引)。
不用担心what if this doesn't work?
原始表会mytable_old
在任何情况下被命名。它可以作为备份。当您知道新表适合您时,可以删除备份。
试试看 !!!
更新2014-06-16 11:13 EDT
如果您担心更大的数据转储,只需gzip。
您可以执行相同的步骤,但如下
步骤01
将数据放入转储文件
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
步骤02
登录到MySQL并运行它
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
步骤03
用数据的附加索引加载表
gzip -d < table_data.sql.gz | mysql -Dmydb
要么
gunzip < table_data.sql.gz | mysql -Dmydb
更新2014-06-16 12:55 EDT
我只是想着与此问题有关的另一个方面。
由于您正在执行DDL而不是DML,因此这可能不是InnoDB内部管道。由于DDL无法为InnoDB回滚,因此问题必须是外部问题。外部管道在哪里堵塞?我怀疑操作系统的临时文件夹。为什么?
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
看到了disk quota exceeded
吗?该磁盘配额在哪里实施?
运行此查询
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
你说是 /var/lib/mysqltmp
现在,在操作系统中运行它
df -h /var/lib/mysqltmp
某些信息告诉我,的空间/var/lib/mysqltmp
已用完毕竟,您只有14G的可用空间。在DDL(用于创建索引)的眼中,发生了回滚,不是在ibdata1文件中,而是在该tmpdir
位置。如果/var/lib/mysqltmp
未安装在任何地方,则将临时数据写入根分区。如果/var/lib/mysqltmp
安装在某处,则该安装中将填充行数据。无论哪种情况,都没有足够的空间来完成DDL。
您有两个选择
选项1
您还可以创建一个大磁盘(也许有100 + GB)并安装/var/lib/mysqltmp
在该大磁盘上。
选项#2
即使您的磁盘空间有限,我的三步建议也应该仍然有效
评论
您发布的错误消息说的可惜
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
这意味着操作系统很好。在这种情况下,也没有任何关联的错误号。
您还应该知道另一件事。MySQL文档说,InnoDB的快速索引创建仍然存在于磁盘上:
在创建索引期间,会将文件写入临时目录(在Unix上为$ TMPDIR,在Windows上为%TEMP%,或--tmpdir配置变量的值)。每个临时文件都足够大,可以容纳构成新索引的一列,并且每个临时文件在合并到最终索引中后都会被删除。
由于MySQL的限制,当您在TEMPORARY TABLE上创建索引时,将复制该表,而不使用“快速索引创建”。据报道这是MySQL Bug#39833。
更新2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
请确保/mnt/cbsvolume1/var/lib/mysql
有100G或更多免费空间