1.工具介绍
正常情况下在线 ALTER 一个表增加一个字段、一个索引的话MySQL 会锁表
使用pt-online-schema-change 在线更新表,不停止业务使用的在线更新表结构:在线 DDL 操作改变表结构并且不阻塞.
2.给表添加表结构。
(1)添加字段前。
mysql> desc t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | MUL | NULL | |
| name | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
(2)添加字段。
[root@mysql1 test]# pt-online-schema-change --user=root --host=192.168.1.51 --port=3306 --password=rootroot --execute --alter "ADD COLUMN member VARCHAR(20)" D=test,t=t2 --no-check-replication-filters
Found 1 slaves:
mysql2 -> 192.168.1.58:3306
Will check slave lag on:
mysql2 -> 192.168.1.58:3306
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `test`.`t2`...
Creating new table...
Created new table test._t2_new OK.
Altering new table...
Altered `test`.`_t2_new` OK.
2023-02-28T10:08:52 Creating triggers...
2023-02-28T10:08:52 Created triggers OK.
2023-02-28T10:08:52 Copying approximately 3 rows...
2023-02-28T10:08:52 Copied rows OK.
2023-02-28T10:08:52 Analyzing new table...
2023-02-28T10:08:52 Swapping tables...
2023-02-28T10:08:52 Swapped original and new tables OK.
2023-02-28T10:08:52 Dropping old table...
2023-02-28T10:08:52 Dropped old table `test`.`_t2_old` OK.
2023-02-28T10:08:52 Dropping triggers...
2023-02-28T10:08:52 Dropped triggers OK.
Successfully altered `test`.`t2`.
mysql> DESC t2;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | varchar(100) | YES | | NULL | |
| member | varchar(20) | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
发现已经添加成功。
(3)更改列
pt-online-schema-change --user=root --host=192.168.1.51 --port=3306 --password=rootroot --execute --alter "MODIFY COLUMN member VARCHAR(30)" D=test,t=t2 --no-check-replication-filters
[root@mysql1 test]# pt-online-schema-change --user=root --host=192.168.1.51 --port=3306 --password=rootroot --execute --alter "MODIFY COLUMN member VARCHAR(30)" D=test,t=t2 --no-check-replication-filters
Found 1 slaves:
mysql2 -> 192.168.1.58:3306
Will check slave lag on:
mysql2 -> 192.168.1.58:3306
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `test`.`t2`...
Creating new table...
Created new table test._t2_new OK.
Altering new table...
Altered `test`.`_t2_new` OK.
2023-02-28T10:13:41 Creating triggers...
2023-02-28T10:13:41 Created triggers OK.
2023-02-28T10:13:41 Copying approximately 3 rows...
2023-02-28T10:13:41 Copied rows OK.
2023-02-28T10:13:41 Analyzing new table...
2023-02-28T10:13:41 Swapping tables...
2023-02-28T10:13:41 Swapped original and new tables OK.
2023-02-28T10:13:41 Dropping old table...
2023-02-28T10:13:41 Dropped old table `test`.`_t2_old` OK.
2023-02-28T10:13:41 Dropping triggers...
2023-02-28T10:13:41 Dropped triggers OK.
Successfully altered `test`.`t2`.
mysql> DESC t2;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | varchar(100) | YES | | NULL | |
| member | varchar(30) | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
发现已经修改成功。
(3)删除列
[root@mysql1 test]# pt-online-schema-change --user=root --host=192.168.1.51 --port=3306 --password=rootroot --execute --alter "DROP COLUMN member " D=test,t=t2 --no-check-replication-filters
Found 1 slaves:
mysql2 -> 192.168.1.58:3306
Will check slave lag on:
mysql2 -> 192.168.1.58:3306
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `test`.`t2`...
Creating new table...
Created new table test._t2_new OK.
Altering new table...
Altered `test`.`_t2_new` OK.
2023-02-28T10:15:58 Creating triggers...
2023-02-28T10:15:58 Created triggers OK.
2023-02-28T10:15:58 Copying approximately 3 rows...
2023-02-28T10:15:58 Copied rows OK.
2023-02-28T10:15:58 Analyzing new table...
2023-02-28T10:15:58 Swapping tables...
2023-02-28T10:15:58 Swapped original and new tables OK.
2023-02-28T10:15:58 Dropping old table...
2023-02-28T10:15:58 Dropped old table `test`.`_t2_old` OK.
2023-02-28T10:15:58 Dropping triggers...
2023-02-28T10:15:58 Dropped triggers OK.
Successfully altered `test`.`t2`.
mysql> DESC t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
删除完成。
3.pt-online-schema-change 其他用法。
(1)增加字段 content
CREATE TABLE `test_pt` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "ADD COLUMN content text" D=test,t=test_pt --no-check-replication-filters \
--alter-foreign-keys-method=auto --recursion-method=none --print --execute
No slaves found. See --recursion-method if host mysql1 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method.
Altering `test`.`test_pt`...
Creating new table...
CREATE TABLE `test`.`_test_pt_new` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Created new table test._test_pt_new OK.
Altering new table...
ALTER TABLE `test`.`_test_pt_new` ADD COLUMN content text
Altered `test`.`_test_pt_new` OK.
2023-02-28T10:26:54 Creating triggers...
2023-02-28T10:26:54 Created triggers OK.
2023-02-28T10:26:54 Copying approximately 1 rows...
INSERT LOW_PRIORITY IGNORE INTO `test`.`_test_pt_new` (`id`, `name`, `age`) SELECT `id`, `name`, `age` FROM `test`.`test_pt` LOCK IN SHARE MODE /*pt-online-schema-change 81063 copy table*/
2023-02-28T10:26:54 Copied rows OK.
2023-02-28T10:26:54 Analyzing new table...
2023-02-28T10:26:54 Swapping tables...
RENAME TABLE `test`.`test_pt` TO `test`.`_test_pt_old`, `test`.`_test_pt_new` TO `test`.`test_pt`
2023-02-28T10:26:54 Swapped original and new tables OK.
2023-02-28T10:26:54 Dropping old table...
DROP TABLE IF EXISTS `test`.`_test_pt_old`
2023-02-28T10:26:54 Dropped old table `test`.`_test_pt_old` OK.
2023-02-28T10:26:54 Dropping triggers...
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_del`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_upd`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_ins`
2023-02-28T10:26:54 Dropped triggers OK.
Successfully altered `test`.`test_pt`.
mysql> desc test_pt;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| content | text | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
(2)删除字段
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "DROP COLUMN content " D=test,t=test_pt --no-check-replication-filters \
--alter-foreign-keys-method=auto --recursion-method=none --quiet --execute
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method
mysql> desc test_pt;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
删除成功。
(3)修改字段
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "MODIFY COLUMN age TINYINT NOT NULL DEFAULT 0" D=test,t=test_pt \
--no-check-replication-filters --alter-foreign-keys-method=auto \
--recursion-method=none --quiet --execute
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method
修改前
mysql> desc test_pt;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
修改后:
mysql> desc test_pt;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| age | tinyint(4) | NO | | 0 | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
(4)字段改名称:将age改成address;
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "CHANGE COLUMN age address varchar(30)" D=test,t=test_pt --no-check-alter \
--no-check-replication-filters --alter-foreign-keys-method=auto --recursion-method=none \
--quiet --execute
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method
修改前:
mysql> desc test_pt;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| age | tinyint(4) | NO | | 0 | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
修改后:
mysql> desc test_pt;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| address | varchar(30) | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
(5)增加索引,在address列上添加索引
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "ADD INDEX idx_address(address)" D=test,t=test_pt --no-check-alter \
--no-check-replication-filters --alter-foreign-keys-method=auto --recursion-method=none \
--print --execute
No slaves found. See --recursion-method if host mysql1 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method.
Altering `test`.`test_pt`...
Creating new table...
CREATE TABLE `test`.`_test_pt_new` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`address` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Created new table test._test_pt_new OK.
Altering new table...
ALTER TABLE `test`.`_test_pt_new` ADD INDEX idx_address(address)
Altered `test`.`_test_pt_new` OK.
2023-02-28T10:39:41 Creating triggers...
2023-02-28T10:39:41 Created triggers OK.
2023-02-28T10:39:41 Copying approximately 1 rows...
INSERT LOW_PRIORITY IGNORE INTO `test`.`_test_pt_new` (`id`, `name`, `address`) SELECT `id`, `name`, `address` FROM `test`.`test_pt` LOCK IN SHARE MODE /*pt-online-schema-change 81730 copy table*/
2023-02-28T10:39:41 Copied rows OK.
2023-02-28T10:39:41 Analyzing new table...
2023-02-28T10:39:41 Swapping tables...
RENAME TABLE `test`.`test_pt` TO `test`.`_test_pt_old`, `test`.`_test_pt_new` TO `test`.`test_pt`
2023-02-28T10:39:41 Swapped original and new tables OK.
2023-02-28T10:39:41 Dropping old table...
DROP TABLE IF EXISTS `test`.`_test_pt_old`
2023-02-28T10:39:41 Dropped old table `test`.`_test_pt_old` OK.
2023-02-28T10:39:41 Dropping triggers...
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_del`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_upd`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_ins`
2023-02-28T10:39:41 Dropped triggers OK.
Successfully altered `test`.`test_pt`.
修改前:
mysql> show indexes from test_pt;
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_pt | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
修改后:
mysql> show indexes from test_pt;
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_pt | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| test_pt | 1 | idx_address | 1 | address | A | 0 | NULL | NULL | YES | BTREE | | |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
(6)删除索引:
pt-online-schema-change --user=root --password=rootroot --host=192.168.1.51 \
--alter "DROP INDEX idx_address" D=test,t=test_pt --no-check-alter \
--no-check-replication-filters --alter-foreign-keys-method=auto --recursion-method=none \
--print --execute
No slaves found. See --recursion-method if host mysql1 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
No foreign keys reference `test`.`test_pt`; ignoring --alter-foreign-keys-method.
Altering `test`.`test_pt`...
Creating new table...
CREATE TABLE `test`.`_test_pt_new` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`address` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_address` (`address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Created new table test._test_pt_new OK.
Altering new table...
ALTER TABLE `test`.`_test_pt_new` DROP INDEX idx_address
Altered `test`.`_test_pt_new` OK.
2023-02-28T10:42:43 Creating triggers...
2023-02-28T10:42:43 Created triggers OK.
2023-02-28T10:42:43 Copying approximately 1 rows...
INSERT LOW_PRIORITY IGNORE INTO `test`.`_test_pt_new` (`id`, `name`, `address`) SELECT `id`, `name`, `address` FROM `test`.`test_pt` LOCK IN SHARE MODE /*pt-online-schema-change 81884 copy table*/
2023-02-28T10:42:43 Copied rows OK.
2023-02-28T10:42:43 Analyzing new table...
2023-02-28T10:42:43 Swapping tables...
RENAME TABLE `test`.`test_pt` TO `test`.`_test_pt_old`, `test`.`_test_pt_new` TO `test`.`test_pt`
2023-02-28T10:42:43 Swapped original and new tables OK.
2023-02-28T10:42:43 Dropping old table...
DROP TABLE IF EXISTS `test`.`_test_pt_old`
2023-02-28T10:42:43 Dropped old table `test`.`_test_pt_old` OK.
2023-02-28T10:42:43 Dropping triggers...
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_del`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_upd`
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_test_pt_ins`
2023-02-28T10:42:43 Dropped triggers OK.
Successfully altered `test`.`test_pt`.
删除前:
mysql> show indexes from test_pt;
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_pt | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| test_pt | 1 | idx_address | 1 | address | A | 0 | NULL | NULL | YES | BTREE | | |
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
删除后:
mysql> show indexes from test_pt;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_pt | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
4.总结
pt-online-schema-change 可以很方便的实现在线对表增加列,但是有个限制条件就是表必须有主键或者唯一索引,
否则添加失败。有主从的环境需要指定: --no-check-replication-filters.
pt-online-schema-change:
1.添加列
2.删除字段
3.修改字段
4.改字段的名称
5.创建索引
6.删除索引