我已经在2010年10月的StackOverflow中解决了这个问题。
请记住InnoDB基础架构中最繁忙的文件:/ var / lib / mysql / ibdata1
该文件通常包含四种类型的信息
- 表数据
- 表索引
- MVCC(多版本并发控制)数据
- 表元数据(表空间ID的列表)
OPTIMIZE TABLE
针对存储在ibdata1中的InnoDB表运行有两件事:
- 使表的数据和索引在ibdata1内部连续,从而可以更快地访问
- 因为连续数据和索引页面已附加到ibdata1,所以它使ibdata1增大
尽管您可以将表数据和表索引与ibdata1分离并使用innodb_file_per_table对其进行独立管理,但ibdata1中巨大的磁盘空间根本不会消失并且无法回收。您必须做更多。
要一劳永逸地收缩ibdata1,您必须执行以下操作:
1)MySQL将所有数据库转储到SQL文本文件中(称为/root/SQLData.sql)
2)删除所有数据库(mysql模式除外)
3)关闭mysql
4)将以下行添加到/etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
旁注:无论您为innodb_buffer_pool_size设置什么,请确保innodb_log_file_size为innodb_buffer_pool_size的25%。
5)删除ibdata1,ib_logfile0和ib_logfile1
此时,/ var / lib / mysql中应该只有mysql模式
6)重新启动mysql
这将以10或18MB(取决于MySQL的版本)重新创建ibdata1,分别以1G重新创建ib_logfile0和ib_logfile1
7)将/root/SQLData.sql重新加载到mysql中
ibdata1将增长,但仅包含表元数据。实际上,随着时间的流逝,它会非常缓慢地增长。ibdata1快速增长的唯一方法是具有以下一项或多项:
- 很多DDL的(
CREATE TABLE
,DROP TABLE
,ALTER TABLE
)
- 大量交易
- 每笔交易有很多更改要提交
每个InnoDB表都将存在于ibdata1之外
假设您有一个名为mydb.mytable的InnoDB表。如果进入/ var / lib / mysql / mydb,将看到代表该表的两个文件
- mytable.frm(存储引擎头)
- mytable.ibd(mydb.mytable的表数据和表索引的主页)
ibdata1将永远不再包含InnoDB数据和索引。
使用/etc/my.cnf中的innodb_file_per_table选项,可以运行OPTIMIZE TABLE mydb.mytable;
,文件/var/lib/mysql/mydb/mytable.ibd实际上会缩小。
作为MySQL DBA,我在职业生涯中做了很多次
实际上,这是我第一次将50GB的ibdata1文件压缩为500MB。
试试看。如果您对此还有其他疑问,请给我发送电子邮件。相信我。这将在短期和长期内起作用!
更新2012-04-19 09:23 EDT
运行上述步骤后,如何确定需要对哪些表进行碎片整理?可以找到答案,但是您将为其编写脚本。
这是一个示例:假设您有table mydb.mytable
。启用innodb_file_per_table后,您将拥有文件/var/lib/mysql/mydb/mytable.ibd
您将必须检索两个数字
来自OS的文件大小:您可以像这样从OS确定文件大小
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
FILESIZE FROM INFORMATION_SCHEMA:您可以像这样从information_schema.tables确定文件大小:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
只需从OS值中减去INFORMATION_SCHEMA值,然后将差值除以INFORMATION_SCHEMA值即可。
从那里,您可以确定认为有必要对表进行碎片整理的百分比。当然,您可以使用以下命令之一对其进行碎片整理:
OPTIMIZE TABLE mydb.mytable;
要么
ALTER TABLE mydb.mytable ENGINE=InnoDB;