为什么 mysql 里的 ibdata1 文件不断的增长?

ibdata1 file

我们在 Percona 支持栏目经常收到关于 MySQL 的 ibdata1 文件的这个问题。

当监控服务器发送一个关于 MySQL 服务器存储的报警时,恐慌就开始了 —— 就是说磁盘快要满了。

一番调查后你意识到大多数地盘空间被 InnoDB 的共享表空间 ibdata1 使用。而你已经启用了 innodb_file_per_table,所以问题是:

ibdata1存了什么?

当你启用了 innodb_file_per_table,表被存储在他们自己的表空间里,但是共享表空间仍然在存储其它的 InnoDB 内部数据:

  • 数据字典,也就是 InnoDB 表的元数据
  • 变更缓冲区
  • 双写缓冲区
  • 撤销日志

其中的一些在 Percona 服务器上可以被配置来避免增长过大的。例如你可以通过 innodb_ibuf_max_size 设置最大变更缓冲区,或设置 innodb_doublewrite_file 来将双写缓冲区存储到一个分离的文件。

MySQL 5.6 版中你也可以创建外部的撤销表空间,所以它们可以放到自己的文件来替代存储到 ibdata1。可以看看这个文档

什么引起 ibdata1 增长迅速?

当 MySQL 出现问题通常我们需要执行的第一个命令是:


  1. SHOW ENGINE INNODB STATUS/G

这将展示给我们一些很有价值的信息。我们从** TRANSACTION(事务)**部分开始检查,然后我们会发现这个:


  1. ---TRANSACTION 36E, ACTIVE 1256288 sec
  2. MySQL thread id 42, OS thread handle 0x7f8baaccc700, query id 7900290 localhost root
  3. show engine innodb status
  4. Trx read view will not see trx with id >= 36F, sees < 36F

这是一个最常见的原因,一个14天前创建的相当老的事务。这个状态是活动的,这意味着 InnoDB 已经创建了一个数据的快照,所以需要在撤销日志中维护旧页面,以保障数据库的一致性视图,直到事务开始。如果你的数据库有大量的写入任务,那就意味着存储了大量的撤销页。

如果你找不到任何长时间运行的事务,你也可以监控INNODB STATUS 中的其他的变量,“History list length(历史记录列表长度)”展示了一些等待清除操作。这种情况下问题经常发生,因为清除线程(或者老版本的主线程)不能像这些记录进来的速度一样快地处理撤销。

我怎么检查什么被存储到了 ibdata1 里了?

很不幸,MySQL 不提供查看什么被存储到 ibdata1 共享表空间的信息,但是有两个工具将会很有帮助。第一个是马克·卡拉汉制作的一个修改版 innochecksum ,它发布在这个漏洞报告里。

它相当易于使用:


  1. # ./innochecksum /var/lib/mysql/ibdata1
  2. 0 bad checksum
  3. 13 FIL_PAGE_INDEX
  4. 19272 FIL_PAGE_UNDO_LOG
  5. 230 FIL_PAGE_INODE
  6. 1 FIL_PAGE_IBUF_FREE_LIST
  7. 892 FIL_PAGE_TYPE_ALLOCATED
  8. 2 FIL_PAGE_IBUF_BITMAP
  9. 195 FIL_PAGE_TYPE_SYS
  10. 1 FIL_PAGE_TYPE_TRX_SYS
  11. 1 FIL_PAGE_TYPE_FSP_HDR
  12. 1 FIL_PAGE_TYPE_XDES
  13. 0 FIL_PAGE_TYPE_BLOB
  14. 0 FIL_PAGE_TYPE_ZBLOB
  15. 0 other
  16. 3 max index_id

全部的 20608 中有 19272 个撤销日志页。这占用了表空间的 93%。

第二个检查表空间内容的方式是杰里米·科尔制作的 InnoDB Ruby 工具。它是个检查 InnoDB 的内部结构的更先进的工具。例如我们可以使用 space-summary 参数来得到每个页面及其数据类型的列表。我们可以使用标准的 Unix 工具来统计撤销日志页的数量:


  1. # innodb_space -f /var/lib/mysql/ibdata1 space-summary | grep UNDO_LOG | wc -l
  2. 19272

尽管这种特殊的情况下,innochedcksum 更快更容易使用,但是我推荐你使用杰里米的工具去了解更多的 InnoDB 内部的数据分布及其内部结构。

好,现在我们知道问题所在了。下一个问题:

我该怎么解决问题?

这个问题的答案很简单。如果你还能提交语句,就做吧。如果不能的话,你必须要杀掉线程开始回滚过程。那将停止 ibdata1 的增长,但是很显然,你的软件会出现漏洞,有些人会遇到错误。现在你知道如何去鉴定问题所在,你需要使用你自己的调试工具或普通的查询日志来找出谁或者什么引起的问题。

如果问题发生在清除线程,解决方法通常是升级到新版本,新版中使用一个独立的清除线程替代主线程。更多信息查看该文档

有什么方法回收已使用的空间么?

没有,目前还没有一个容易并且快速的方法。InnoDB 表空间从不收缩...参见10 年之久的漏洞报告,最新更新自詹姆斯·戴(谢谢):

当你删除一些行,这个页被标为已删除稍后重用,但是这个空间从不会被回收。唯一的方法是使用新的 ibdata1 启动数据库。要做这个你应该需要使用 mysqldump 做一个逻辑全备份,然后停止 MySQL 并删除所有数据库、ib_logfile*、ibdata1* 文件。当你再启动 MySQL 的时候将会创建一个新的共享表空间。然后恢复逻辑备份。

总结

当 ibdata1 文件增长太快,通常是 MySQL 里长时间运行的被遗忘的事务引起的。尝试去解决问题越快越好(提交或者杀死事务),因为不经过痛苦缓慢的 mysqldump 过程,你就不能回收浪费的磁盘空间。

也是非常推荐监控数据库以避免这些问题。我们的 MySQL 监控插件包括一个 Nagios 脚本,如果发现了一个太老的运行事务它可以提醒你。

原文发布时间为:2015-07-16




本文来自合作伙伴“Linux中国

时间: 2024-10-12 00:56:26

为什么 mysql 里的 ibdata1 文件不断的增长?的相关文章

解决MySQL数据库目录ibdata1文件占用空间大问题

经常使用MySQL并启用了InnoDB引擎的时候,会发现数据库相应目录下,ibdata1这个文件会越来越大,并且即便删除表中数据也无法减小其空间占用.所以,接下来的配置就是为了解决这个问题. 1.先停止所有访问数据库的服务: 2.导出数据文件: mysqldump -u root -p dbname| gzip > dbname.sql.gz 该命令会将数据库压缩导出,会慢点,如果你数据库并不大的话,可以不用压缩,那么就是: mysqldump -u root -p dbname > dbna

mysql ibdata1文件太大,沾满磁盘空间,再有数据往里写的时候怎么处理。?菜鸟求解决!

问题描述 mysql ibdata1文件太大,沾满磁盘空间,再有数据往里写的时候怎么处理.?菜鸟求解决! 前两天遇到mysql ibdata1文件太大,沾满磁盘空间的问题,本人是卸载然后停服务器,再删除那几个文件的处理.如果项目上线,出现这种情况,再有数据往里写的时候怎么处理.?菜鸟求解决!

MySQL的InnoDB扩容及ibdata1文件瘦身方案完全解析_Mysql

mysql的innodb扩容为了添加一个数据文件到表空间中,首先要关闭 MySQL 数据库,编辑 my.cnf 文件,确认innodb ibdata文件的实际情况和my.cnf的配置是否一致,这里有两种情况: 1.my.cnf的配置 innodb_data_file_path=ibdata1:10G;ibdata2:10G:autoextend 如果当前数据库正在使用ibdata1,或者使用ibdata2,但ibdata2没有超过10G,则对my.cnf配置直接改成: innodb_data_f

MySql ibdata1文件瘦身

原文地址:MySql ibdata1文件太大如何缩小 MySql innodb如果是共享表空间,ibdata1文件越来越大,达到了30多个G,对一些没用的表进行清空: truncate table xxx; 然后optimize table xxx; 没有效果 因为对共享表空间不起作用. mysql ibdata1存放数据,索引等,是MYSQL的最主要的数据. 如果不把数据分开存放的话,这个文件的大小很容易就上了G,甚至几十G.对于某些应用来说,并不是太合适.因此要把此文件缩小. 无法自动收缩,

PHP FOR MYSQL 代码生成助手(根据Mysql里的字段自动生成类文件的)_php技巧

根据 Mysql 里的字段 自动生成 类文件: 但需要导入: require_once ./db/ez_sql_core.php;require_once ./db/ez_sql_mysql.php; 帮助文档:http://jvmultimedia.com/docs/ezsql/ez_sql_help.htm  上图 : 核心代码: 复制代码 代码如下: <?php class db{ /*****************************************************

mysql 体系结构以及各种文件类型学习汇总

1.mysql体系结构 由数据库和数据库实例组成,是单进程多线程架构. 数据库:物理操作系统文件或者其他文件的集合,在mysql中,数据库文件可以是frm.myd.myi.ibd等结尾的文件,当使用ndb存储引擎的时候,不是os文件,是存放于内存中的文件. 数据库实例:由数据库后台进程/线程以及一个共享内存区组成,共享内存可以被运行的后台线程/进程所共享 2.mysql文件类型 mysql主要文件类型有如下几种: 参数文件:mysql实例启动的时候在哪里可以找到数据库文件,并且指定某些初始化参数

ibdata1文件持续增加的问题定位

用户的ibdata1文件持续增加: Innodb的表有两种存放方式: 第一种共享表空间方式:所有表的索引,数据统一存放在一个共享表空间中,这样会导致共享表空间的空间迅速增长,同时空间回收困难: 第二种独占表空间方式:就是RDS目前采用 的,也就是一张表一个表空间,表中的索引和数据存放在自己独立的表空间中,空间能够比较容易的回收: 无论是独占还是共享表空间,innodb都会有系统共享表空间(ibdata1),该系统表空间主要用于存储数据字典,undo entry,insert buffer,dou

mysql 里executeQuery在for循环里执行失效怎么解决?

问题描述 mysql 里executeQuery在for循环里执行失效怎么解决? 问题就是,之前是有时候可以上传图片,并被数据库记录,但会经常图片上传成功,数据库记录却没有. 在javabean的数据库里是这样创建conn 和 st 及rs的: public ft_con(){ if(conn==null){ try{ //Class.forName("com.microsoft.sqlserver.jdbc"); 基本不使用. //Class.forName("com.mi

mysql-请问往MYSQL里导入一个SQL表,为什么会报这个错误?

问题描述 请问往MYSQL里导入一个SQL表,为什么会报这个错误? 开始导入----------> 然后就提示--------> 文件路径: 我选择的路径没错额:D:源代码下载存储day7-mysql多表资料与作业EMPDEPT.sql 信息日志如下: [Err] 1051 - Unknown table 'dept' [Err] -- ---------------------------- -- Table structure for DEPT DROP TABLE DEPT; CREAT