mysql online ddl和pt_MySQL变更之:Online DDL 和 PT-OSC 该选谁?
參考:
在MySQL 5.6版本以前,最昂貴的數(shù)據(jù)庫操作之一就是執(zhí)行數(shù)據(jù)定義語言(DDL,例如CREATE,DROP,ALTER等)語句,特別是ALTER語句,因?yàn)樵谛薷谋頃r(shí),MySQL會阻塞整個(gè)表的讀寫操作。
對于巨大的表,可能需要幾個(gè)小時(shí)才能完成表的DDL,如此勢必會影響應(yīng)用程序,因此需要對這些操作進(jìn)行良好的規(guī)劃,以避免在高峰時(shí)段進(jìn)行這些更改。對于那些有全天候服務(wù)(24*7)或有限維護(hù)時(shí)間的人來說,大表上的DDL是一場真正的噩夢。
Percona開發(fā)了一個(gè)非常好的工具,稱為 pt-online-schema-change,在線執(zhí)行此類操作,而不會阻塞或影響應(yīng)用程序,且允許對正在更改的表進(jìn)行讀/寫操作。
MySQL也對DDL語句進(jìn)行了一些增強(qiáng),并在MySQL 5.6中引入了在線DDL功能。
PT-ONLINE-SCHEMA-CHANGE
OVERVIEW
pt-osc 用于 alter table 時(shí)不鎖表,簡單地說,這個(gè)工具創(chuàng)建一個(gè)與原始表一樣的新的空表,并根據(jù)需要更改表結(jié)構(gòu),然后將原始表中的數(shù)據(jù)以小塊形式復(fù)制到新表中,然后刪除原始表,然后將新表重命名為原始名稱。在復(fù)制過程中,對原始表的所有新的更改(insert,delete,update)都將應(yīng)用于新表,因?yàn)樵谠急砩蟿?chuàng)建了一個(gè)觸發(fā)器,以確保所有新的更改都將應(yīng)用于新表。有關(guān) pt-online-schema-change 工具的更多信息,請查閱手冊文檔?。大致的工作流程總結(jié)如下:
pt-osc工作過程
創(chuàng)建一個(gè)和要執(zhí)行 alter 操作的表一樣的新的空表結(jié)構(gòu)(是alter之前的結(jié)構(gòu))
在新表執(zhí)行alter table 語句(速度應(yīng)該很快)
在原表中創(chuàng)建觸發(fā)器3個(gè)觸發(fā)器分別對應(yīng)insert,update,delete操作
以一定塊大小從原表拷貝數(shù)據(jù)到臨時(shí)表,拷貝過程中通過原表上的觸發(fā)器在原表進(jìn)行的寫操作都會更新到新建的臨時(shí)表(會限制每次拷貝數(shù)據(jù)的行數(shù)以保證拷貝不會過多消耗服務(wù)器資源,采用 LOCK IN SHARE MODE 來獲取要拷貝數(shù)據(jù)段的最新數(shù)據(jù)并對數(shù)據(jù)加共享鎖阻止其他會話修改數(shù)據(jù),不過每次加S鎖的行數(shù)不多,很快就會被釋放)
Rename 原表到old表中,在把臨時(shí)表Rename為原表(整個(gè)過程只在rename表的時(shí)間會鎖一下表,其他時(shí)候不鎖表)
如果有參考該表的外鍵,根據(jù)alter-foreign-keys-method參數(shù)的值,檢測外鍵相關(guān)的表,做相應(yīng)設(shè)置的處理
默認(rèn)最后將舊原表刪除
EXAMPLE
給表 test.scutech 的 name 字段加一個(gè)索引 idx_name (下面的輸出完整的描述了該工具在后臺執(zhí)行的所有步驟):
# pt-online-schema-change --print --execute --alter="add index idx_name(name)" D=test,t=scutech,h=localhost,u=root,p=xxxxxxNo slaves found. See--recursion-method if host CentOS6.6-zabbix has slaves.
Not checking slave lag because no slaves were found and--check-slave-lag was not specified.
Operation, tries,wait:
analyze_table,10, 1copy_rows,10, 0.25create_triggers,10, 1drop_triggers,10, 1swap_tables,10, 1update_foreign_keys,10, 1Altering `test`.`scutech`...
Creating new table...
CREATE TABLE `test`.`_scutech_new` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`number`int(11) DEFAULT NULL,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4
Created new table test._scutech_new OK.
Altering new table...
ALTER TABLE `test`.`_scutech_new` add index idx_name(name)
Altered `test`.`_scutech_new` OK.2018-05-11T17:15:18Creating triggers...
CREATE TRIGGER `pt_osc_test_scutech_del` AFTER DELETE ON `test`.`scutech` FOR EACH ROW DELETE IGNORE FROM `test`.`_scutech_new` WHERE `test`.`_scutech_new`.`id` <=> OLD.`id`
CREATE TRIGGER `pt_osc_test_scutech_upd` AFTER UPDATE ON `test`.`scutech` FOR EACH ROW BEGIN DELETE IGNORE FROM `test`.`_scutech_new` WHERE!(OLD.`id` <=> NEW.`id`) AND `test`.`_scutech_new`.`id` <=> OLD.`id`;REPLACE INTO `test`.`_scutech_new` (`id`, `number`, `name`) VALUES (NEW.`id`, NEW.`number`, NEW.`name`);END
CREATE TRIGGER `pt_osc_test_scutech_ins` AFTER INSERT ON `test`.`scutech` FOR EACH ROW REPLACE INTO `test`.`_scutech_new` (`id`, `number`, `name`) VALUES (NEW.`id`, NEW.`number`, NEW.`name`)2018-05-11T17:15:18Created triggers OK.2018-05-11T17:15:18 Copying approximately 9977440rows...
INSERT LOW_PRIORITY IGNORE INTO `test`.`_scutech_new` (`id`, `number`, `name`) SELECT `id`, `number`, `name` FROM `test`.`scutech` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) AND ((`id` <= ?)) LOCK IN SHARE MODE /*pt-online-schema-change 124376 copy nibble*/SELECT/*!40001 SQL_NO_CACHE*/ `id` FROM `test`.`scutech` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) ORDER BY `id` LIMIT ?, 2 /*next chunk boundary*/Copying `test`.`scutech`:12% 03:24remain
Copying `test`.`scutech`:26% 02:49remain
Copying `test`.`scutech`:38% 02:22remain
Copying `test`.`scutech`:48% 02:09remain
Copying `test`.`scutech`:58% 01:46remain
Copying `test`.`scutech`:65% 01:33remain
Copying `test`.`scutech`:72% 01:19remain
Copying `test`.`scutech`:78% 01:04remain
Copying `test`.`scutech`:86% 00:43remain
Copying `test`.`scutech`:92% 00:25remain2018-05-11T17:20:43Copied rows OK.2018-05-11T17:20:44Analyzing new table...2018-05-11T17:20:44Swapping tables...
RENAME TABLE `test`.`scutech` TO `test`.`_scutech_old`, `test`.`_scutech_new` TO `test`.`scutech`2018-05-11T17:20:45Swapped original and new tables OK.2018-05-11T17:20:45Dropping old table...
DROP TABLE IF EXISTS `test`.`_scutech_old`2018-05-11T17:20:46Dropped old table `test`.`_scutech_old` OK.2018-05-11T17:20:46Dropping triggers...
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_scutech_del`;
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_scutech_upd`;
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_scutech_ins`;2018-05-11T17:20:46Dropped triggers OK.
Successfully altered `test`.`scutech`.
PT-ONLINE-SCHEMA-CHANGE 的局限性
在使用此工具之前,應(yīng)為表定義PRIMARY KEY或唯一索引,因?yàn)樗荄ELETE觸發(fā)器所必需的;
如果表已經(jīng)定義了觸發(fā)器,則不支持 pt-osc ;(顯然不是不能有任何觸發(fā)器,只是不能有針對insert、update、delete的觸發(fā)器存在,因?yàn)橐粋€(gè)表上不能有兩個(gè)相同類型的觸發(fā)器)
如果表具有外鍵約束,需要使用選項(xiàng) --alter-foreign-keys-method ;
還是因?yàn)橥怄I,對象名稱可能會改變(indexes names 等);
在Galera集群環(huán)境中,不支持更改MyISAM表,系統(tǒng)變量 wsrep_OSU_method 必須設(shè)置為 TOI(total order isolation)。
ONLINE DDL
OVERVIEW
在MySQL 5.6中,引入了在線 DDL方法,以便訪問和寫入正在更改的表。在線DDL語法與指定兩個(gè)參數(shù)后的正常 alter語句完全相同:
ALGORITHM:
INPLACE:?表的更改將在原表進(jìn)行,而不用重建整個(gè)表格(在大多數(shù)情況下,不需要將數(shù)據(jù)復(fù)制到臨時(shí)表)
COPY:?將數(shù)據(jù)復(fù)制到臨時(shí)表中,重建表格并重建二級索引(相當(dāng)于傳統(tǒng)方法)
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 在手冊文檔中有詳細(xì)說明,您可以在這里查看更多信息。
哪些 ddl 操作可以使用 inplace算法?
EXAMPLE
給表 test.test2 的 name 字段加一個(gè)索引 name_idx
mysql> alter tabletest2-> add index name_idx (name),algorithm=inplace, lock=none;
Query OK,0 rows affected (0.03sec)
Records:0 Duplicates: 0 Warnings: 0
僅適用于InnoDB(語法上它可以與其他存儲引擎一起使用,如MyISAM,但MyISAM只允許algorithm = copy,與傳統(tǒng)方法相同);
無論使用何種鎖(NONE,共享或排它),在開始和結(jié)束時(shí)都需要一個(gè)短暫的時(shí)間來鎖表(排它鎖);參考這里
在添加/刪除外鍵時(shí),應(yīng)該禁用 foreign_key_checks 以避免表復(fù)制;
仍然有一些 alter 操作需要 copy 或 lock 表(老方法), 有關(guān)哪些表更改需要表復(fù)制或表鎖定,請查看手冊;
如果在表上有 ON ... CASCADE 或 ON ... SET NULL 約束,則在 alter table 語句中不允許LOCK = NONE;
Online DDL 會被復(fù)制到從庫(同主庫一樣,如果 LOCK = NONE,從庫也不會加鎖),但復(fù)制本身將被阻止,因?yàn)?alter 在從庫以單線程執(zhí)行,這將導(dǎo)致主從延遲問題。
COMPARISON RESULTS
下圖是 Online DDL 和 PT-OSC 的一些操作的比較,表有 1,078,880 行。
rows affected 為 0,說明使用 in-place 方法,非0 則使用 copy-table 方法。當(dāng)?rows affected 非0 時(shí),建議使用 pt-osc 進(jìn)行表變更。
另外,如果原表已經(jīng)是 InnoDB 引擎,執(zhí)行?alter table tb_name engine=innodb; 影響的行數(shù)是 0 ,可以使用 in-place ,此方法可以清理表空間的磁盤碎片。
WHICH METHOD SHOULD BE USED?
雖然pt-online-schema-change允許對被修改的表進(jìn)行讀寫操作,但它仍然將表數(shù)據(jù)復(fù)制到后臺的臨時(shí)表中,這會在MySQL服務(wù)器上增加開銷。 所以基本上,如果Online DDL不能有效地工作,我們才應(yīng)該使用pt-online-schema-change。換句話說,如果在線DDL需要將數(shù)據(jù)復(fù)制到臨時(shí)表(algorithm=copy),并且該表將被阻塞很長一段時(shí)間(lock = exclusive)或者在復(fù)制環(huán)境中更改大表時(shí),則應(yīng)該使用 pt-online-schema-change 工具。
使用 pt-osc 和原生 5.6 online ddl相比,如何選擇?
online ddl在必須copy table時(shí)成本較高,不宜采用
pt-osc工具在存在觸發(fā)器時(shí),不適用
修改索引、外鍵、列名時(shí),優(yōu)先采用online ddl,并指定 ALGORITHM=INPLACE
其它情況使用pt-osc,雖然存在copy data
pt-osc比online ddl要慢一倍左右,因?yàn)樗歉鶕?jù)負(fù)載調(diào)整的
無論哪種方式都選擇的業(yè)務(wù)低峰期執(zhí)行
特殊情況需要利用主從特性,先alter從庫,再改原主庫(sql_log_bin),可避免主從延遲
在執(zhí)行 ALTER TABLE 語句時(shí),如果不清楚是否可以用上 Online DDL 的 inplace 算法,可以直接在語句后面加上 ALGORITHM = INPLACE,如果語句不能使用 in-place 機(jī)制,該語句會立即停止。
總結(jié)
以上是生活随笔為你收集整理的mysql online ddl和pt_MySQL变更之:Online DDL 和 PT-OSC 该选谁?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql回滚与错误提示_对mysql事
- 下一篇: mysql中合并函数_MYSQL分组合并