关于 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 出现问题通常我们需要执行的第一个命令是:
-
SHOW ENGINE INNODB STATUS
/
G
这将展示给我们一些很有价值的信息。我们从** TRANSACTION(事务)**部分开始检查,然后我们会发现这个:
-
---
TRANSACTION
36E
,
ACTIVE
1256288
sec
-
MySQL
thread
id
42
,
OS thread handle
0x7f8baaccc700
,
query
id
7900290
localhost root
-
show engine innodb status
-
Trx
read view will
not
see trx
with
id
>=
36F
,
sees
<
36F
这是一个最常见的原因,一个14天前创建的相当老的事务。这个状态是
活动的
,这意味着 InnoDB 已经创建了一个数据的快照,所以需要在
撤销
日志中维护旧页面,以保障数据库的一致性视图,直到事务开始。如果你的数据库有大量的写入任务,那就意味着存储了大量的撤销页。
如果你找不到任何长时间运行的事务,你也可以监控INNODB STATUS 中的其他的变量,“
History list length(历史记录列表长度)
”展示了一些等待清除操作。这种情况下问题经常发生,因为清除线程(或者老版本的主线程)不能像这些记录进来的速度一样快地处理撤销。
我怎么检查什么被存储到了 ibdata1 里了?
很不幸,MySQL 不提供查看什么被存储到 ibdata1 共享表空间的信息,但是有两个工具将会很有帮助。第一个是马克·卡拉汉制作的一个修改版 innochecksum ,它发布在
这个漏洞报告
里。
它相当易于使用:
-
#
./
innochecksum
/
var
/
lib
/
mysql
/
ibdata1
-
0
bad checksum
-
13
FIL_PAGE_INDEX
-
19272
FIL_PAGE_UNDO_LOG
-
230
FIL_PAGE_INODE
-
1
FIL_PAGE_IBUF_FREE_LIST
-
892
FIL_PAGE_TYPE_ALLOCATED
-
2
FIL_PAGE_IBUF_BITMAP
-
195
FIL_PAGE_TYPE_SYS
-
1
FIL_PAGE_TYPE_TRX_SYS
-
1
FIL_PAGE_TYPE_FSP_HDR
-
1
FIL_PAGE_TYPE_XDES
-
0
FIL_PAGE_TYPE_BLOB
-
0
FIL_PAGE_TYPE_ZBLOB
-
0
other
-
3
max index_id
全部的 20608 中有 19272 个撤销日志页。
这占用了表空间的 93%
。
第二个检查表空间内容的方式是杰里米·科尔制作的
InnoDB Ruby 工具
。它是个检查 InnoDB 的内部结构的更先进的工具。例如我们可以使用 space-summary 参数来得到每个页面及其数据类型的列表。我们可以使用标准的 Unix 工具来统计
撤销日志
页的数量:
-
#
innodb_space
-
f
/
var
/
lib
/
mysql
/
ibdata1 space
-
summary
|
grep
UNDO_LOG
|
wc
-
l
-
19272
尽管这种特殊的情况下,innochedcksum 更快更容易使用,但是我推荐你使用杰里米的工具去了解更多的 InnoDB 内部的数据分布及其内部结构。
好,现在我们知道问题所在了。下一个问题:
我该怎么解决问题?
这个问题的答案很简单。如果你还能提交语句,就做吧。如果不能的话,你必须要杀掉线程开始回滚过程。那将停止 ibdata1 的增长,但是很显然,你的软件会出现漏洞,有些人会遇到错误。现在你知道如何去鉴定问题所在,你需要使用你自己的调试工具或普通的查询日志来找出谁或者什么引起的问题。
如果问题发生在清除线程,解决方法通常是升级到新版本,新版中使用一个独立的清除线程替代主线程。更多信息查看该
文档
有什么方法回收已使用的空间么?
没有,目前还没有一个容易并且快速的方法。InnoDB 表空间从不收缩...参见
10 年之久的漏洞报告
,最新更新自詹姆斯·戴(谢谢):
当你删除一些行,这个页被标为已删除稍后重用,但是这个空间从不会被回收。唯一的方法是使用新的 ibdata1 启动数据库。要做这个你应该需要使用 mysqldump 做一个逻辑全备份,然后停止 MySQL 并删除所有数据库、ib_logfile*
、
ibdata1* 文件。当你再启动 MySQL 的时候将会创建一个新的共享表空间。然后恢复逻辑备份。
当 ibdata1 文件增长太快,通常是 MySQL 里长时间运行的被遗忘的事务引起的。尝试去解决问题越快越好(提交或者杀死事务),因为不经过痛苦缓慢的 mysqldump 过程,你就不能回收浪费的磁盘空间。
也是非常推荐监控数据库以避免这些问题。我们的
MySQL 监控插件
包括一个 Nagios 脚本,如果发现了一个太老的运行事务它可以提醒你。
============================
这两种文件都是存放Innodb 数据的文件
,之所以有两种文件来存放Innodb 的数据(包
括索引),是因为Innodb 的数据存储方式能够通过配置来决定是使用共享表空间存放存储数
据,还是独享表空间存放存储数据。
独享表空间存储方式使用“.ibd”文件来存放数据,且
每个表一个“.ibd”文件,文件存放在和MyISAM 数据相同的位置
。
如果选用共享存储表空
间来存放数据,则会使用ibdata 文件来存放,所有表共同使用一个(或者多个,可自行配
置)ibdata 文件
。
ibdata 文件可以通过innodb_data_home_dir 和innodb_data_file_path
两个参数共同配置组成, innodb_data_home_dir 配置数据存放的总目录, 而
innodb_data_file_path 配置每一个文件的名称。当然, 也可以不配置
innodb_data_home_dir 而直接在innodb_data_file_path 参数配置的时候使用绝对路径来
完成配置。innodb_data_file_path 中可以一次配置多个ibdata 文件。
文件可以是指定大
小,也可以是自动扩展的,但是Innodb 限制了仅仅只有最后一个ibdata 文件能够配置成自
动扩展类型。当我们需要添加新的ibdata 文件的时候,只能添加在innodb_data_file_path
配置的最后,而且必须重启MySQL 才能完成ibdata 的添加工作。
不过如果我们使用独享表
空间存储方式的话,就不会有这样的问题,但是如果要使用裸设备的话,每个表一个裸设备,
可能造成裸设备数量非常大,而且不太容易控制大小,实现比较困难,而共享表空间却不会
有这个问题,容易控制裸设备数量。我个人还是更倾向于使用独享表空间存储方式。当然,
两种方式各有利弊,看大家各自应用环境的侧重点在那里了。
上面仅仅介绍了两种最常用存储引擎的数据文件,此外其他各种存储引擎都有各自的数
据文件,读者朋友可以自行创建某个存储引擎的表做一个简单的测试,做更多的了解。
关于 MySQL 的 ibdata1 文件的这个问题:当监控服务器发送一个关于 MySQL 服务器存储的报警时,恐慌就开始了 —— 就是说磁盘快要满了。一番调查后你意识到大多数地盘空间被 InnoDB 的共享表空间 ibdata1 使用。而你已经启用了 innodb_file_per_table,所以问题是:ibdata1存了什么?当你启用了 innodb_file_per_table,表被存储在...
处理
MySQL
的
ibdata
1文件过大问题
本人遇到一次在安装zabbix监控的时候,yum安装的
MySQL
数据库,后面用了一段时间发现data目录下的
ibdata
1的空间特别大,反而我的zabbix数据库的空间很小,这样的情况在后面备份zabbix数据库的时候会很不方便,所以想着要怎么解决下。
ibdata
1文件是什么?
ibdata
1是一个用来构建innodb系统表空间的文件,这个文...
共享表空间就是
ibdata
1,独立表空间放在每个表的.ibd(数据和索引)和.frm(表结构)为后缀的文件中。
单独的表空间只存储该表的数据,索引和插入缓冲的BITMAP等信息,其余还放在共享表空间中。
所以:innodb 的表,直接复制文件是无法使用的,会提示 table doesn’t exists ,在复制的时候,应将data目录下的
ibdata
1 文件一并复制过去,并且删除 ib_logfile0 、ib_logfile1 文件
Mysql
ibdata
1即Innodb data1缩写,是innodb引擎的表空间,用于存放
数据字典Data dictionary: 只读的表,存储对象的相关信息,如占用空间,列的缺省值,约束信息,用户名,权限,审计信息等;
双写缓冲区 Double write buffer:; Innodb写入数据默认是16k/pages为一个单位写入,而磁盘是4k/page一...
ibdata
1文件是什么?
ibdata
1是一个用来构建innodb系统表空间的文件,这个文件包含了innodb表的元数据、undo日志、修改buffer和双写buffer。随着数据库的使用,
ibdata
1文件会越来越大,innodb_autoextend_increment选项则指定了该文件每次自动增长的步进,默认是8M.
熟悉Oracle的亲,可以把
ibdata
理解成redo日志。
my.cnf中的参数设置形式:
innodb_data_file_path =
ibdata
1:256M;
ibdata
2:
mysql
innodb的表由.frm .ibd 组成,frm:存了每个表的元数据,包括表结构的定义等;ibd:存了每个表的元数据,包括表结构的定义等;
ibd文件结构由segment inode、extent和page组成。
通过py_innodb_page_info可以查看某张表的ibd结构,如下面这个例子:
page offset 00000000, page type <File S...
ibdata
1是
MySQL
数据库中的一个文件,它包含了InnoDB存储引擎的表空间数据。如果
ibdata
1文件损坏了,我们可以尝试以下几种方法来恢复数据。
首先,备份是非常重要的。如果你有完整的备份,你可以简单地将备份文件恢复到一个新的
MySQL
实例中,从而解决损坏的问题。
如果没有备份,可以尝试使用
MySQL
自带的工具来修复损坏的
ibdata
1文件。
首先,关闭
MySQL
服务器,确保没有任何对数据库文件的写操作。然后备份整个数据目录,以防万一。
然后,使用innodb_force_recovery选项将数据库启动到恢复模式。这将尝试修复损坏的数据,并尽可能多地恢复数据。
如果恢复模式无法修复数据库,我们可以尝试使用InnoDB启动选项来创建一个新的
ibdata
1文件,然后重新导入数据。首先,在
MySQL
配置文件中设置innodb_force_recovery选项的值为最高值(一般是6),然后启动
MySQL
服务器。这将尝试最大程度地恢复数据库。然后使用
mysql
dump命令将所有数据导出到一个文件中。接下来,停止
MySQL
服务器,将innodb_force_recovery选项设回默认值,删除原来的数据目录,创建一个新的数据目录,并将从备份导出的数据放入新的数据目录下。最后,重新启动
MySQL
服务器,数据将被导入到新的数据库中。
尽管这些方法可能能够恢复部分数据,但它们并不是100%可靠的。在尝试修复损坏的数据库之前,最好先与专业的数据库管理员咨询,以获取更确切和个性化的建议。