online ddl與pt-osc詳解

Ⅰ、背景

優化sql的過程當中發現表上少一個索引,直接加一個?會不會hang住?不加?sql又跑很差,由此引出一個問題——ddl操做怎麼作?mysql

Ⅱ、閒扯三兩句

  • 5.6版本以前的MySQL建立索引不支持online,會對錶加一個讀鎖(S lock),只能select,insert會阻塞,5.6開始,MySQL原生支持了在線索引添加,在添加索引過程當中,應用程序對錶依然可讀可寫
  • online ddl的這段時間內,對錶作的操做會先記錄到alter table的日誌裏,這個日誌是內存的,若是內存大小過小記不下來就會報錯
show variables like 'innodb%max%';
innodb_online_alter_log_max_size | 134217728

若是線上更新操做比較多,調大這個值 set global innodb_online_alter_log_max_size = 128M,這是個全局變量,在my.cnf中也配上算法

Ⅲ、老式DDL

3.1 鎖模式與算法解析

一、兩個參數:lock和algorithm
鎖模式:sql

模式 含義
default 根據事務最大併發判斷用什麼模式
none 不加任何鎖,不阻塞
shared 共享模式,和5.1的fast index creation同樣,可讀,但不支持dml
exclusive 排他模式,任何操做都不支持

算法:centos

算法 含義
default 根據old_alter_table決定用哪一個算法,off爲用新算法,即inplace
inplace 共享鎖,只支持增長和刪除索引兩種操做
copy 須要拷貝數據,效率低

無論用什麼模式,online ddl開始以前都會有一個短期的排他鎖,結束以前也同樣,因此說,操做以前須要確保沒有大事務執行,不然會出現嚴重阻塞session

二、兩種算法添加索引步驟對比(5.5版本)併發

- copy inplace
1 新建帶索引的臨時表 建立索引數據字典(只能是二級索引,若是是主鍵指定inplace也會轉爲copy)
2 鎖原表,禁止DML,容許查詢 加共享鎖,禁止DML,容許查詢
3 將原表數據拷貝到臨時表 讀取聚簇索引,構造新的索引項,排序並插入新索引
4 升級shared鎖爲exclusive,禁止讀寫,作rename(修改數據字典,很快) 等待打開當前表的全部只讀事務提交
5 完成建立索引操做 建立索引結束

三、語法:oracle

alter table tb_name ...
lock = xxx,algorithm = xxx
注意:多個ddl操做建議放到一條語句種執行,效率比分開執行高

tips:
以上分析是針對5.5及以前的狀況,即那時候只有增長、刪除索引不須要拷貝原表,但也不能操做DMLapp

Ⅳ、現代online ddl的分類與實現細節

4.1 分類

online ddl包含copy和inplace兩種socket

修改列類型和刪除主鍵用copy工具

inplace又分爲rebuild和no-rebuild兩種

rebuild須要重建表,修改記錄格式,添加、刪除列、修改默認值都用rebuild

no-rebuild只須要修改元數據,添加、刪除索引、修改列名則用no-rebuild

rebuild方式比no-rebuild方式實質多了一個ddl執行階段

4.2 實現細節(三階段)

先檢測一些命名、長度等限制

- prepare ddl commit
1 server層建立臨時frm 降級exclusive-mdl鎖,容許讀寫(copy不可寫) 升級exclusive-mdl鎖,禁止讀寫
2 持有exclusive-mdl鎖,禁止讀寫 掃描原表的聚簇索引每條記錄 應用最後row_log種產生的日誌
3 根據alter類型,肯定執行方式(copy,inplace-rebuild,inplace-norebuild) 遍歷新表的聚簇索引和二級索引 更新innodb的數據字典
4 更新數據字典的內存對象 根據記錄構造對應的索引項 提交事務(刷新事務的redo日誌)
5 分配row_log對象記錄增量 將索引項插入sort_buffer塊 修改統計信息
6 innodb層生成臨時ibd文件(rebuild狀況下) 將sort_buffer塊插入新的索引 rename臨時idb、frm文件
7 數據字典上提交事務、釋放鎖 處理ddl執行過程種產生的增量(rebuild狀況下) 變動完成

4.3 注意三個參數

參數 -
old_alter_table 默認off即用inplace模式
tmpdir 建立索引時排序的內存不夠則在此目錄作
innodb_online_alter_log_max_size 存row_log

tips:
②online ddl中inplace是優選項,ALGORITHM=COPY定會拷貝表,只讀,但ALGORITHM=INPLACE也可能拷貝表,但能夠併發DML(由於有row_log)
③5.6依然不支持online的ddl操做:修改列的數據類型,刪除主鍵,變動表字符集
④inplace對dml的支持比較好,但消耗卻比copy大

online ddl關鍵點小結

①數據完整性--->row_log
②online和數據一致性--->propare和commit時短暫mdl,幾乎全程online
③server和innodb一致--->prepare時server生成frm,innodb生成臨時ibd,ddl時原表拷貝到ibd,row_log應用到ibd,commit時innodb修改數據字典,提交,最後innodb和server重命名ibd和rfm

Ⅴ、pt-osc

5.1 爲何要用pt-osc

問題:
在線索引添加存在的一個問題——主從延時(MySQL邏輯複製,oracle物理複製不存在這個問題)

緣由:
alter table是執行完以後才告訴從機要執行(事務),從庫再順序執行。
若是是copy的那種online ddl,執行到這個ddl,其餘並行的dml語句則要等待這個ddl執行完畢後才能繼續(看上文原理),以下圖:

主從延遲的產生:
 +------------------------+
 |          master        |       o_ddl_5min
 +------------------------+
            |   |
            |log|        同步的是二進制日誌,要等事務執行完以後才提交過去,和物理日誌不一樣           
            |   |
 +------------------------+
 |          slave         |       o_ddl_5min
 +------------------------+

所以,即便5.7如今對愈來愈多的ddl操做讀寫不阻塞了,真正在線上也不多用alter table這種方式去執行ddl操做

目前咱們經常使用的一個工具是pt-osc

這個工具作在線ddl,主從延遲很是小,它不是直接操做的,是經過觸發器的機制來慢慢作,還有專門控制延遲的參數

5.2 安裝與操做演示

yum install -y perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-Time-HiRes perl-DBI perl-DBD-MySQL

cd /usr/local/src
wget https://www.percona.com/downloads/percona-toolkit/3.0.4/binary/tarball/percona-toolkit-3.0.4_x86_64.tar.gz
tar zxvf percona-toolkit-3.0.4_x86_64.tar.gz
cd percona-toolkit-3.0.4
perl Makefile.PL
make
make install

pt-online-schema-change --alter "convert to character set utf8b4" D=test,t=a  
顯示操做步驟,真正執行要加 --excute
pt-online-schema-change --alter "dd index index_a (a)" D=test,t=a --excute
整個過程拆成不少小的步驟,一個一個傳到從上去,因此延遲比較小,缺點是時間長

tips:
percona toolkit中最有用的就是pt-online-schema-change,其餘工具官方工具包utlities裏面都有了,儘可能用官方的,另外官方也在作osc了

5.3 原理淺析

方案:

步驟 操做
step1 sysbench導入測試數據到test庫sbtest1中
step2 開啓general_log,並輸出到mysql.general_log表
step3 osc給sbtest1表的c字段加一個索引(能夠把execute換作--dry-run)
step4 分析glog
step1:略

step2:
(root@localhost) [(none)]> truncate mysql.general_log;
Query OK, 0 rows affected (1.65 sec)

(root@localhost) [(none)]> set global general_log = 1;
Query OK, 0 rows affected (0.00 sec)

(root@localhost) [(none)]> set global log_output = 'table';
Query OK, 0 rows affected (0.01 sec)

step 3:
pt-online-schema-change --alter "add index index_c (c)" --socket=/tmp/mysql.sock --user=root --password=123  D=test,t=sbtest1 --execute
No slaves found.  See --recursion-method if host VM_221_162_centos 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
Altering `test`.`sbtest1`...
Creating new table...
Created new table test._sbtest1_new OK.
Altering new table...
Altered `test`.`_sbtest1_new` OK.
2017-11-30T18:28:19 Creating triggers...
2017-11-30T18:28:19 Created triggers OK.
2017-11-30T18:28:19 Copying approximately 493200 rows...
2017-11-30T18:28:41 Copied rows OK.
2017-11-30T18:28:41 Analyzing new table...
2017-11-30T18:28:41 Swapping tables...
2017-11-30T18:28:41 Swapped original and new tables OK.
2017-11-30T18:28:41 Dropping old table...
2017-11-30T18:28:41 Dropped old table `test`.`_sbtest1_old` OK.
2017-11-30T18:28:41 Dropping triggers...
2017-11-30T18:28:41 Dropped triggers OK.
Successfully altered `test`.`sbtest1`.

上面已經能夠看出個大概過程了

step 4:
這一步詳細分5塊分析以下:
(root@localhost) [(none)]> set global log_output = 'file';
Query OK, 0 rows affected (0.00 sec)

(root@localhost) [(none)]> set global general_log = 0;
Query OK, 0 rows affected (0.01 sec)

(root@localhost) [mysql]> select argument from mysql.general_log;

 root@localhost on test using Socket                                                                
 set autocommit=1                                                                               
 SHOW VARIABLES LIKE 'innodb\_lock_wait_timeout'                                                
 SET SESSION innodb_lock_wait_timeout=1                                                             
 SHOW VARIABLES LIKE 'lock\_wait_timeout'                                                   
 SET SESSION lock_wait_timeout=60                                                                   
 SHOW VARIABLES LIKE 'wait\_timeout'                                                            
 SET SESSION wait_timeout=10000                                                                 
 SELECT @@SQL_MODE                                                                                  
 SET @@SQL_QUOTE_SHOW_CREATE = 1/*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'*/                        
 SELECT @@server_id /*!50038 , @@hostname*/  

說明:
一、設置session級的變量
 SET SESSION innodb_lock_wait_timeout=1  
 SET SESSION lock_wait_timeout=60  
 SET SESSION wait_timeout=10000 
 
 -----------------------------------------
 
 SHOW VARIABLES LIKE 'version%'                                                                  
 SHOW ENGINES                                                                                   
 SHOW VARIABLES LIKE 'innodb_version'                                                           
 SHOW VARIABLES LIKE 'innodb_stats_persistent'                                                  
 SELECT @@SERVER_ID                                                                             
 SHOW GRANTS FOR CURRENT_USER()                                                                     
 SHOW FULL PROCESSLIST                                     
 SHOW SLAVE HOSTS                                                                                 
 SHOW GLOBAL STATUS LIKE 'Threads_running'                                                       
 SHOW GLOBAL STATUS LIKE 'Threads_running'                           
 SELECT CONCAT(@@hostname, @@port)                                                           
 SHOW TABLES FROM `test` LIKE 'sbtest1'                                  
 SELECT VERSION()                                       
 SHOW TRIGGERS FROM `test` LIKE 'sbtest1'                                                   
 /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */                                                              
 USE `test`                                                             
 SHOW CREATE TABLE `test`.`sbtest1`                                       
 /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */                 
 EXPLAIN SELECT * FROM `test`.`sbtest1` WHERE 1=1                                    
 SELECT table_schema, table_name FROM information_schema.key_column_usage WHERE referenced_table_schema='test' AND referenced_table_name='sbtest1'                               
 SHOW VARIABLES LIKE 'wsrep_on'                                                                    
 /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */ 
 
說明:
一、查看變量,當前用戶的權限,slave信息,版本信息等
二、檢查sbtest1是否存在觸發器
三、執行計劃
四、檢查sbtest1是否存在外鍵關聯

 -----------------------------------------

 USE `test`                                 
 SHOW CREATE TABLE `test`.`sbtest1`                                                             
 /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */                 
 CREATE TABLE `test`.`_sbtest1_new` (
`id` int(11) NOT NULL AUTO_INCREMENT,
    `k` int(11) NOT NULL DEFAULT '0',
      `c` char(120) NOT NULL DEFAULT '',
        `pad` char(60) NOT NULL DEFAULT '',
          PRIMARY KEY (`id`),
            KEY `k_1` (`k`)
            ) ENGINE=InnoDB AUTO_INCREMENT=500001 DEFAULT CHARSET=latin1 
 ALTER TABLE `test`.`_sbtest1_new` add index index_c (c)                                            
 /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */                                                                 
 USE `test`                                                                                 
 SHOW CREATE TABLE `test`.`_sbtest1_new`                                    
 /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */                 
 
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'DELETE'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1'  
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'UPDATE'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1'  
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'INSERT'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1'  
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'DELETE'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1' 
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'UPDATE'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1' 
 SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'INSERT'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'test'    AND EVENT_OBJECT_TABLE = 'sbtest1' 
 
 CREATE TRIGGER `pt_osc_test_sbtest1_del` AFTER DELETE ON `test`.`sbtest1` FOR EACH ROW DELETE IGNORE FROM `test`.`_sbtest1_new` WHERE `test`.`_sbtest1_new`.`id` <=> OLD.`id`          
 CREATE TRIGGER `pt_osc_test_sbtest1_upd` AFTER UPDATE ON `test`.`sbtest1` FOR EACH ROW BEGIN DELETE IGNORE FROM `test`.`_sbtest1_new` WHERE !(OLD.`id` <=> NEW.`id`) AND `test`.`_sbtest1_new`.`id` <=> OLD.`id`;REPLACE INTO `test`.`_sbtest1_new` (`id`, `k`, `c`, `pad`) VALUES (NEW.`id`, NEW.`k`, NEW.`c`, NEW.`pad`);END              
 CREATE TRIGGER `pt_osc_test_sbtest1_ins` AFTER INSERT ON `test`.`sbtest1` FOR EACH ROW REPLACE INTO `test`.`_sbtest1_new` (`id`, `k`, `c`, `pad`) VALUES (NEW.`id`, NEW.`k`, NEW.`c`, NEW.`pad`)
 
 說明:
 一、根據原表的表結構結建立一張新表
 二、對新表上的c字段加索引,這裏依然用的是alter
 三、檢查原表上觸發器狀況,5.6開始同一張表上不能存在同一個動做的觸發器
 四、針對新表建立三個觸發器,DELETE,UPDATE和INSERT(重點看下三個觸發器內容)

 -----------------------------------------
 
 EXPLAIN SELECT * FROM `test`.`sbtest1` WHERE 1=1                                                 
 SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) ORDER BY `id` LIMIT 1 /*first lower boundary*/                                       
 SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX (`PRIMARY`) WHERE `id` IS NOT NULL ORDER BY `id` LIMIT 1 /*key_len*/                              
 
 EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ * FROM `test`.`sbtest1` FORCE INDEX (`PRIMARY`) WHERE `id` >= '1' /*key_len*/                                               
 EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/                                 
 SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/                                        
 EXPLAIN SELECT `id`, `k`, `c`, `pad` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) LOCK IN SHARE MODE /*explain pt-online-schema-change 16157 copy nibble*/                                  
 INSERT LOW_PRIORITY IGNORE INTO `test`.`_sbtest1_new` (`id`, `k`, `c`, `pad`) SELECT `id`, `k`, `c`, `pad` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) LOCK IN SHARE MODE /*pt-online-schema-change 16157 copy nibble*/                             
 SHOW WARNINGS                                                                          
 SHOW GLOBAL STATUS LIKE 'Threads_running'       
 
 EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) ORDER BY `id` LIMIT 3787, 2 /*next chunk boundary*/                             
 SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) ORDER BY `id` LIMIT 3787, 2 /*next chunk boundary*/                                      
 EXPLAIN SELECT `id`, `k`, `c`, `pad` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) AND ((`id` <= '4788')) LOCK IN SHARE MODE /*explain pt-online-schema-change 16157 copy nibble*/                                                                     
 INSERT LOW_PRIORITY IGNORE INTO `test`.`_sbtest1_new` (`id`, `k`, `c`, `pad`) SELECT `id`, `k`, `c`, `pad` FROM `test`.`sbtest1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) AND ((`id` <= '4788')) LOCK IN SHARE MODE /*pt-online-schema-change 16157 copy nibble*/               
 SHOW WARNINGS                                                                                 
 SHOW GLOBAL STATUS LIKE 'Threads_running'  
 
 說明:
 一、chunk太多,此處只貼兩組
 二、以chunk爲單位進行目標表數據的拷貝(根據pk或uk分片),有專門的參數指定怎麼分片
 三、在拷貝的過程當中,對目標表的相關記錄加了lock in share mode mode保證數據一致性,此時,會堵塞客戶端對這些記錄的DML操做
 四、LOW_PRIORITY插入,下降優先級插入,等表上無其餘操做時才插
 五、SHOW GLOBAL STATUS LIKE 'Threads_running'檢查當前正在運行的Threads數量,默認Threads_running=25,若是未指定最大值,則會取當前值的120%做爲最大值,若是超過閥值則會暫停數據拷貝
 六、不少explain語句?緣由是沒指定chunk大小,第一次默認分1000條記錄,後面chunk具體多少根據執行計劃判斷成本,不影響系統正常運行則執行insert

 -----------------------------------------

 RENAME TABLE `test`.`sbtest1` TO `test`.`_sbtest1_old`, `test`.`_sbtest1_new` TO `test`.`sbtest1` 
 DROP TABLE IF EXISTS `test`.`_sbtest1_old`                                                       
 DROP TRIGGER IF EXISTS `test`.`pt_osc_test_sbtest1_del`                            
 DROP TRIGGER IF EXISTS `test`.`pt_osc_test_sbtest1_upd`                                         
 DROP TRIGGER IF EXISTS `test`.`pt_osc_test_sbtest1_ins`                                            
 SHOW TABLES FROM `test` LIKE '\_sbtest1\_new' 

說明:
一、ANALYZE更新新表的統計信息
二、新老兩張表重命名
三、刪除原表
四、刪除觸發器

5.4 osc小結

general log種已經算比較詳細了,但不一樣參數可能結果仍是會有很多區別,此處很少分析,精簡一下osc的幾個重要的步驟以下:

步驟 操做
step1 檢查原表是否由主鍵和觸發器
step2 建立tmp-S數據表
step3 在S表上建立insert update delete觸發器
step4 全量數據同步過去
step5 全量同步的過程當中,新產生的增量(變化)數據就觸發到tmp-S表中
step6 新舊錶重命名(元數據鎖,短暫鎖表)
step7 刪除舊錶,刪除觸發器

重點提煉:
一、如何保證全量先過去仍是增量先過去?
insert、update兩個觸發器都是replace機制,解決了增量先於全量致使數據不對的問題
好比update一條記錄,全量的還沒進來,你update啥呢?是空數據,就不執行,但不要緊,我先把最新數據插進去,全量過來衝突了就ignore,此時無主鍵就會致使數據錯誤
ignore表示出錯了,不會返回出錯信息,直接忽略
update的ignore:增量數據先執行了,又接着導原來的數據進去可能會主鍵衝突
delete的ignore:導入過程當中,原表一條數據被刪除,以後的導入過程當中已經沒有這條記錄了,那麼新表中delete時找不到該記錄

二、怎樣保證limit 1000 數據一致?
數據一致是由lock in share mode保證

三、爲何不直接先全量後增量?
很差控制,先建觸發器,因此確定有增量比全量之先過去,若是觸發器後建,那導入全量的時候產生的增量又沒辦法弄了

四、osc的一些限制 ①表上必定要有主鍵(操做主鍵有風險需注意) 一方面chunck分片時要用主鍵,另外一方面下降數據錯誤的風險 ②表上有外鍵怎麼辦? --alter-foreign-keys-metho=rebuild_constraints ③原表不能存在觸發器 同一個表不能存在同一類型的觸發器(5.7版本已經沒有這個限制) ④只支持innodb,而且實例上空閒空間大於原表1倍以上

相關文章
相關標籤/搜索