mysql export import_[MySQL 5.6] Innodb新特性之export/import 表文件-阿里云开发者社区

以下分析及实验基于MySQL5.6.12

用法:

简单的实验了一把,使用sysbench创建的表

mysql>  FLUSH TABLES sbtest1 FOR EXPORT;

Query OK, 0 rows affected (0.00 sec)

观察到sb库下产生的新文件:

$ ls -lh sbtest1.*

-rw-rw—- 1 mysql dba  563 Jun 10 10:29 sbtest1.cfg

-rw-rw—- 1 mysql dba 8.5K Jun  7 11:29 sbtest1.frm

-rw-rw—- 1 mysql dba 276M Jun  9 00:49 sbtest1.ibd

.cfg包含了Innodb的数据词典信息,例如有多少列,数据类型及顺序是什么,以及包含哪些索引等等。

将ibd和cfg文件拷贝后,执行unlock tables,注意unlock操作会移除cfg文件

目标库上,建立对应的空表:

mysql> CREATE TABLE `sbtest1` (

->   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

->   `k` int(10) unsigned NOT NULL DEFAULT ‘0’,

->   `c` char(120) NOT NULL DEFAULT ”,

->   `pad` char(60) NOT NULL DEFAULT ”,

->   PRIMARY KEY (`id`),

->   KEY `k` (`k`)

-> ) ENGINE=InnoDB;

Query OK, 0 rows affected (0.09 sec)

mysql> alter table sbtest1 discard tablespace;

Query OK, 0 rows affected (0.04 sec)

将sbtest1.cfg和sbtest1.ibd拷贝到这实例数据目录上面,修改好对应的权限,然后执行。

mysql> alter table sbtest1 import tablespace;

Query OK, 0 rows affected (3.49 sec)

mysql> select count(*) from sbtest1;

+———-+

| count(*) |

+———-+

|  1000000 |

+———-+

1 row in set (1.01 sec)

不过其实cfg文件也不是必须要和ibd文件一一对应

同样的,重新创建表,只拷贝ibd文件:

mysql>  alter table sbtest1 import tablespace;

Query OK, 0 rows affected, 1 warning (4.01 sec)mysql> show warnings;

+———+——+———————————————————————————————————————————————-+

| Level   | Code | Message                                                                                                                                      |

+———+——+———————————————————————————————————————————————-+

| Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory) Error opening ‘./test/sbtest1.cfg’, will attempt to import without schema verification |

+———+——+———————————————————————————————————————————————-+

1 row in set (0.00 sec)

提示没有sbtest1.cfg,但是数据已经完整的插入进去了。实际上tablespace 的Import功能很早就有了,但MySQL5.5及之前的版本存在几点限制:

1.如果目标实例上表在tablespace中存储的id和ibd中的id不匹配,则会导入失败,通常的做法是通过不断创建/rename表的方式推高table id,或者直接改ibd文件头的方式来让其匹配;

2.如果没有主键的话,还要考虑到全局row id的问题;

3.迁移表的ibd上的最大LSN不能超过目标机器的LSN;

4. change buffer导致的DML缓存,脏页等问题。

另外cfg文件也不是必须的,因为他只是从ibdata中抽取的表的定义,但如果表空间也损坏了呢?这种情况下可能就没有作用了。

很显然早就有人意识到这个问题,看看这个bug report http://bugs.mysql.com/bug.php?id=66715, 如果知道表的schema的话,我们就可以在另外一个实例上生成一个cfg文件,因为cfg并不要求和ibd文件是完全对应的。

不过,一个明显的问题是,如果表空间损坏,实例起不来,做不了crash recovery,那么change buffer的操作可能也没有同步到ibd中,这种情况,是不是意味着数据丢失呢?

PS:执行flush tables tbname with read lock也同样会生成cfg文件

简单的跟了下代码

a.  FLUSH TABLES sbtest1 FOR EXPORT

server层的入口函数为flush_tables_for_export

Innodb层进行处理的backtrace为:

flush_tables_for_export->open_and_lock_tables->lock_tables->mysql_lock_tables->lock_external->handler::ha_external_lock->ha_innobase::external_lock

switch (prebuilt->table->quiesce) { case QUIESCE_START: /* Check for FLUSH TABLE t WITH READ LOCK; */ if (!srv_read_only_mode && thd_sql_command(thd) == SQLCOM_FLUSH && lock_type == F_RDLCK) { row_quiesce_table_start(prebuilt->table, trx); /* Use the transaction instance to track UNLOCK TABLES. It can be done via START TRANSACTION; too implicitly. */ ++trx->flush_tables; } break; case QUIESCE_COMPLETE: /* Check for UNLOCK TABLES; implicit or explicit or trx interruption. */ if (trx->flush_tables > 0 && (lock_type == F_UNLCK || trx_is_interrupted(trx))) { row_quiesce_table_complete(prebuilt->table, trx); ut_a(trx->flush_tables > 0); --trx->flush_tables; } break;

其中,row_quiesce_table_start是执行flush table for export的逻辑,row_quiesce_table_complete是unlock tables调用的逻辑

代码在 @file row/row0quiesce.cc 中

a1) row_quiesce_table_start

主要做以下几件事情

*停止purge操作

if (trx_purge_state() != PURGE_STATE_DISABLED) { trx_purge_stop(); }

因此在完成copy后,需要及时的Unlock tables,防止purge线程停止太久,导致history list过长

*合并change buffer :ibuf_contract_in_background(table->id, TRUE)

*确保所有的脏页都刷到磁盘

buf_LRU_flush_or_remove_pages(

table->space, BUF_REMOVE_FLUSH_WRITE, trx);

*写cfg文件

row_quiesce_write_cfg(table, trx->mysql_thd

row_quiesce_write_header:cfg文件头包括cfg文件版本号IB_EXPORT_CFG_VERSION_V1,当前服务器的hostname,表名,下一个自增列的值,page size, table flag,以及列的个数

row_quiesce_write_table:写入表的列的属性信息,包括长度,类型,位置等

row_quiesce_write_indexes:写入每个索引的元数据信息

a2)row_quiesce_table_complete(执行Unlock tables)

*删除cfg文件(os_file_delete_if_exists)

*继续purge操作(trx_purge_run())

b.import数据

backtrace为:

ha_innobase::discard_or_import_tablespace->row_import_for_mysql

大概看了下,主要包括以下几个步骤:

*读取cfg文件,读取的数据保存到结构体row_import中

err = row_import_read_cfg(table, trx->mysql_thd, cfg);

*检查表的定义和cfg中的是否匹配

*扫描ibd文件中的所有page,检查其是否corruption

*检查ibuf bitmap,如果有标记为IBUF_BITMAP_BUFFERED的,表示存在change buffer的操作没有merge进来,可能会丢失数据。

仅仅写日志提示,可以继续正常import数据

*调整聚集索引的segment header,例如其中记录的space id

err = btr_root_adjust_on_import(index);

*purge 聚集索引上的标记删除记录

*调整二级索引根节点和叶子节点segment header,更新space id, purgw标记删除的无效记录

*确保当前实例下一个可用的DB_ROW_ID 要大于当前import的表上最大的DB_ROW_ID

*将产生的脏页刷到磁盘,并从buffer pool中移除对应的page

buf_LRU_flush_or_remove_pages(

prebuilt->table->space, BUF_REMOVE_FLUSH_WRITE, trx);

*更新系统表SYS_INDEXES中记录的索引信息

err = row_import_update_index_root(trx, table, false, true);

*移除表的discade标记

//

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值