参考:
http://www.fromdual.ch/online-ddl_vs_pt-online-schema-change
在MySQL 5.6版本以前,最昂贵的数据库操作之一就是执行数据定义语言(DDL,例如CREATE,DROP,ALTER等)语句,特别是ALTER语句,因为在修改表时,MySQL会阻塞整个表的读写操作。
对于巨大的表,可能需要几个小时才能完成表的DDL,如此势必会影响应用程序,因此需要对这些操作进行良好的规划,以避免在高峰时段进行这些更改。对于那些有全天候服务(24*7)或有限维护时间的人来说,大表上的DDL是一场真正的噩梦。
Percona开发了一个非常好的工具,称为 pt-online-schema-change,在线执行此类操作,而不会阻塞或影响应用程序,且允许对正在更改的表进行读/写操作。
MySQL也对DDL语句进行了一些增强,并在MySQL 5.6中引入了在线DDL功能。
PT-ONLINE-SCHEMA-CHANGE
OVERVIEW
pt-osc 用于 alter table 时不锁表,简单地说,这个工具创建一个与原始表一样的新的空表,并根据需要更改表结构,然后将原始表中的数据以小块形式复制到新表中,然后删除原始表,然后将新表重命名为原始名称。在复制过程中,对原始表的所有新的更改(insert,delete,update)都将应用于新表,因为在原始表上创建了一个触发器,以确保所有新的更改都将应用于新表。有关 pt-online-schema-change 工具的更多信息,请查阅手册文档 。大致的工作流程总结如下:
pt-osc工作过程
- 创建一个和要执行 alter 操作的表一样的新的空表结构(是alter之前的结构)
- 在新表执行alter table 语句(速度应该很快)
- 在原表中创建触发器3个触发器分别对应insert,update,delete操作
- 以一定块大小从原表拷贝数据到临时表,拷贝过程中通过原表上的触发器在原表进行的写操作都会更新到新建的临时表
- Rename 原表到old表中,在把临时表Rename为原表
- 如果有参考该表的外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,做相应设置的处理
- 默认最后将旧原表删除
EXAMPLE
给表 test.test1 的 name 字段加一个索引 name_idx (下面的输出完整的描述了该工具在后台执行的所有步骤):
[root@gcservera ~]# pt-online-schema-change --execute --alter "add index name_idx (name)" D=test,t=test1,h=localhost Operation, tries, wait: copy_rows, 10, 0.25 create_triggers, 10, 1 drop_triggers, 10, 1 swap_tables, 10, 1 update_foreign_keys, 10, 1 Altering `test`.`test1`... Creating new table... Created new table test._test1_new OK. Altering new table... Altered `test`.`_test1_new` OK. 2014-02-09T15:33:27 Creating triggers... 2014-02-09T15:33:27 Created triggers OK. 2014-02-09T15:33:27 Copying approximately 1 rows... 2014-02-09T15:33:27 Copied rows OK. 2014-02-09T15:33:27 Swapping tables... 2014-02-09T15:33:27 Swapped original and new tables OK. 2014-02-09T15:33:27 Dropping old table... 2014-02-09T15:33:27 Dropped old table `test`.`_test1_old` OK. 2014-02-09T15:33:27 Dropping triggers... 2014-02-09T15:33:27 Dropped triggers OK. Successfully altered `test`.`test1`.
PT-ONLINE-SCHEMA-CHANGE 的局限性
- 在使用此工具之前,应为表定义PRIMARY KEY或唯一索引,因为它是DELETE触发器所必需的;
- 如果表已经定义了触发器,则不支持 pt-osc ;
- 如果表具有外键约束,需要使用选项 --alter-foreign-keys-method ;
- 还是因为外键,对象名称可能会改变(indexes names 等);
- 在Galera集群环境中,不支持更改MyISAM表,系统变量 wsrep_OSU_method 必须设置为 TOI(total order isolation)。
ONLINE DDL
OVERVIEW
在MySQL 5.6中,引入了在线 DDL方法,以便访问和写入正在更改的表。在线DDL语法与指定两个参数后的正常 alter语句完全相同:
ALGORITHM:
- INPLACE: 表的更改将在原表进行,而不用重建整个表格(在大多数情况下,不需要将数据复制到临时表)
- COPY: 将数据复制到临时表中,重建表格并重建二级索引(相当于传统方法)
LOCK:
- NONE: Read and write operations are allowed during the altering process.
- SHARED: Only read operations are allowed during the altering operations (DML is not allowed).
- EXCLUSIVE: The entire table will be locked for both reading and writing (neither select nor DML are allowed).
Online DDL 在手册文档中有详细说明,您可以在这里查看更多信息。
EXAMPLE
给表 test.test2 的 name 字段加一个索引 name_idx
mysql> alter table test2 -> add index name_idx (name),algorithm=inplace, lock=none; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0
- 仅适用于InnoDB(语法上它可以与其他存储引擎一起使用,如MyISAM,但MyISAM只允许algorithm = copy,与传统方法相同);
- 无论使用何种锁(NONE,共享或排它),在开始和结束时都需要一个短暂的时间来锁表(排它锁);
- 在添加/删除外键时,应该禁用 foreign_key_checks 以避免表复制;
- 仍然有一些 alter 操作需要 copy 或 lock 表(老方法), 有关哪些表更改需要表复制或表锁定,请查看手册;
- 如果在表上有 ON ... CASCADE 或 ON ... SET NULL 约束,则在 alter table 语句中不允许LOCK = NONE;
- Online DDL 会被复制到从库(同主库一样,如果 LOCK = NONE,从库也不会加锁),但复制本身将被阻止,因为 alter 在从库以单线程执行,这将导致主从延迟问题。
COMPARISON RESULTS
下图是 Online DDL 和 PT-OSC 的一些操作的比较,表有 1,078,880 行。
WHICH METHOD SHOULD BE USED?
虽然pt-online-schema-change允许对被修改的表进行读写操作,但它仍然将表数据复制到后台的临时表中,这会在MySQL服务器上增加开销。 所以基本上,如果Online DDL不能有效地工作,我们才应该使用pt-online-schema-change。换句话说,如果在线DDL需要将数据复制到临时表(algorithm=copy),并且该表将被阻塞很长一段时间(lock = exclusive)或者在复制环境中更改大表时,则应该使用 pt-online-schema-change 工具。