本文介紹如何處理使用PolarDB-X 1.0時出現的DDL異常情況。
DDL原理簡介
PolarDB-X 1.0的DDL指令會在所有分表上執行對應的DDL操作。失敗的情況可以分為兩類:
- DDL在分庫執行失敗。DDL在任意分庫執行出錯都可能導致各分表結構不一致。
分庫執行報錯的原因多種多樣,如建表時表已存在、加列時列已存在等各類衝突或磁碟空間不足等。
- 執行長時間無響應。在對大表執行DDL操作時,有可能由於分庫的執行時間過長導致DDL長時間無響應。
長時間無響應一般是由分庫的執行時間過長導致的。以MySQL為例,DDL的耗時大部分取決於該操作是In-Place(直接在源表修改)還是Copy Table(拷貝表資料)。In-Place只需要修改中繼資料就可以了,而Copy Table需要重建整張表資料,此外還涉及日誌和buffer操作。各類操作與這兩項因素的關係詳見MySQL官方文檔Online DDL Operations。
判斷DDL操作是In-place還是Copy Table操作,可以查看操作結束後rows affected
這一項的傳回值。樣本如下:
- 改變某列的預設值(非常快,完全不會影響表資料)。
Query OK, 0 rows affected (0.07 sec)
- 增加一個索引(需要一點時間 ,但是
0 rows affected
說明表資料沒有被複製)。Query OK, 0 rows affected (21.42 sec)
- 改變某列的資料類型(耗費大量時間並且需要重建表中的所有資料行)。
Query OK, 1671168 rows affected (1 min 35.54 sec)
- 複製表結構產生一張複製表。
- 插入一些資料。
- 在複製表上執行目標DDL操作。
- 檢查操作完成後
rows affected
值是否為0。非0的值表示該操作需要重建整張表,這時可能需要考慮在業務低峰期執行該操作。
PolarDB-X 1.0 DDL操作會將所有SQL分發到所有分庫上並存執行。任一分庫上執行失敗不會影響其他分庫。另外,PolarDB-X 1.0還提供了CHECK TABLE指令來檢測分表結構的一致性。因此,失敗的DDL操作可以重新執行,已經執行成功的分庫上失敗報錯並不會影響其他分庫。只需保證最終所有分表結構一致即可。
DDL執行失敗處理步驟
- 使用CHECK TABLE指令檢查表結構。如果返回結果只有一行且為狀態正常則可認為表狀態一致。此時執行步驟2,否則執行步驟3。
- 使用SHOW CREATE TABLE指令檢查表結構。如果顯示的表結構符合DDL執行後的預期則可認為DDL執行成功,否則繼續執行步驟3。
- 使用SHOW PROCESSLIST指令查看所有當前執行的SQL狀態。如有仍在執行的DDL操作,請等候其執行完成後再執行步驟1、2,檢查表結構是否符合預期,否則執行步驟4。
- 在PolarDB-X 1.0上重新執行DDL操作。如果出現
Lock conflict
的報錯資訊請執行步驟5,否則執行步驟3。 - 使用RELEASE DBLOCK指令釋放DDL操作鎖,然後執行步驟4。
詳細操作如下:
- 檢查表結構一致性。
使用CHECK TABLE指令檢查表結構,樣本如下:
check table `xxxx`;
說明 如果在DMS上執行CHECK TABLE沒有返回結果,請在命令列下重試。若返回結果只有一行且顯示狀態OK時,表明表結構一致。樣本如下:
+----------------------------+-------+----------+----------+ | TABLE | OP | MSG_TYPE | MSG_TEXT | +----------------------------+-------+----------+----------+ | TDDL5_APP.xxxx | check | status | OK | +----------------------------+-------+----------+----------+ 1 row in set (0.05 sec)
- 檢查表結構。
使用SHOW CREATE TABLE指令檢查表結構,樣本如下:
mysql> show create table `xxxx`;
若表結構一致且表結構無誤時,可認為DDL已執行成功,返回結果樣本如下:
+---------+------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+------------------------------------------------------------------------------------------------------------------+ | xxxx | CREATE TABLE `xxxx` ( `id` int(11) NOT NULL DEFAULT '0', `NAME` varchar(1024) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) tbpartition by hash(`id`) tbpartitions 3 | +---------+------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.05 sec)
- 查看當前正在執行的SQL語句。
有些DDL執行速度過慢,發現DDL長時間無響應後,可執行SHOW PROCESSLIST指令查看所有當前執行的SQL狀態,樣本如下:
mysql> SHOW PROCESSLIST WHERE COMMAND != 'Sleep';
返回結果樣本如下:
+---------------+-----------+--------------------+-------------+---------+-----------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+-----------+---------------+-----------+ | ID | USER | DB | COMMAND | TIME | STATE | INFO | ROWS_SENT | ROWS_EXAMINED | ROWS_READ | +---------------+-----------+--------------------+-------------+---------+-----------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+-----------+---------------+-----------+ | 0-0-352724126 | ifisibhk0 | test_123_wvvp_0000 | Query | 15 | Sending data | /*DRDS /42.120.74.88/ac47e5a72801000/ */select `t_item`.`detail_url`,SUM(`t_item`.`price`) from `t_i | NULL | NULL | NULL | | 0-0-352864311 | cowxhthg0 | NULL | Binlog Dump | 13 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL | NULL | NULL | NULL | | 0-0-402714566 | ifisibhk0 | test_123_wvvp_0005 | Query | 14 | Sending data | /*DRDS /42.120.74.88/ac47e5a72801000/ */select `t_item`.`detail_url`,`t_item`.`price` from `t_i | NULL | NULL | NULL | | 0-0-402714795 | ifisibhk0 | test_123_wvvp_0005 | Alter | 114 | Sending data | /*DRDS /42.120.74.88/ac47e5a72801000/ */ALTER TABLE `Persons` ADD `Birthday` date | NULL | NULL | NULL | ...... +---------------+-----------+--------------------+-------------+---------+-----------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+-----------+---------------+-----------+ 12 rows in set (0.03 sec)
TIME列代表該指令已經執行的秒數。發現耗時較長的指令(如樣本中ID為
0-0-402714795
的指令)後,您可使用KILL '0-0-402714795'命令來取消該指令。說明 PolarDB-X 1.0中一個邏輯SQL對應多條分庫指令,因此為了停止一個邏輯DDL可能需要Kill多條指令。您可以從SHOW PROCESSLIST結果集的INFO列判斷該指令歸屬的邏輯SQL。 Lock conflict
報錯處理。PolarDB-X 1.0執行DDL操作會加庫級鎖,操作完後再釋放掉。KILL DDL操作很可能會導致該鎖沒有釋放,此時再執行DDL會出現以下報錯:
Lock conflict , maybe last DDL is still running
此時執行RELEASE DBLOCK命令釋放該鎖即可。指令取消及鎖釋放後,您可以選擇在業務低穀或者停止期間,重新執行該DDL。
常見問題
- Q:為什麼在DMS或其它用戶端上無法顯示修改後的表結構?
A:為了相容某些用戶端從系統資料表(如COLUMNS或TABLES)中擷取表結構的功能,PolarDB-X 1.0在您的0分庫RDS裡建立了一個影子庫,影子庫名與PolarDB-X 1.0邏輯庫名一致,儲存了邏輯庫裡所有的表結構等資訊。
DMS會從影子庫系統資料表中擷取PolarDB-X 1.0的表結構。在處理異常DDL過程中,由於種種原因可能會出現庫表結構已經修改,但是影子庫中的表結構卻未修改的現象。此時您需串連到影子庫,在該庫中重新對錶進行一次DDL操作即可。
說明 CHECK TABLE不會檢測影子庫表結構與PolarDB-X 1.0邏輯庫表結構是否一致。 - Q:執行DDL語句時出現錯誤碼,該如何解決?
A:關於PolarDB-X 1.0返回的常見錯誤碼及解決方案,請參見錯誤碼。