本文介绍如何处理使用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操作前,可以先通过以下步骤判定这是一个快速还是慢速的操作:
  1. 复制表结构生成一张克隆表。
  2. 插入一些数据。
  3. 在克隆表上执行目标DDL操作。
  4. 检查操作完成后rows affected值是否为0。非0的值意味着该操作需要重建整张表,这时可能需要考虑在业务低峰期执行该操作。

PolarDB-X 1.0 DDL操作会将所有SQL分发到所有分库上并行执行。任一分库上执行失败不会影响其他分库。另外,PolarDB-X 1.0还提供了CHECK TABLE指令来检测分表结构的一致性。因此,失败的DDL操作可以重新执行,已经执行成功的分库上失败报错并不会影响其他分库。只需保证最终所有分表结构一致即可。

DDL失败处理步骤

  1. 使用CHECK TABLE指令检查表结构。如果返回结果只有一行且为状态正常则可认为表状态一致。此时进行步骤2,否则进行步骤3。
  2. 使用SHOW CREATE TABLE指令检查表结构。如果显示的表结构符合DDL执行后的预期则可认为DDL执行成功,否则继续进行步骤3。
  3. 使用SHOW PROCESSLIST指令观察所有当前执行的SQL状态。如有仍在执行的DDL操作,请等候其执行完成后再进行步骤1、2,检查表结构是否符合预期,否则进行步骤4。
  4. PolarDB-X 1.0上重新执行DDL操作。如果出现Lock conflict的报错请进行步骤5,否则进行步骤3。
  5. 使用RELEASE DBLOCK指令释放DDL操作锁,然后进行步骤4。

详细操作如下:

  1. 检查表结构一致性。

    使用CHECK TABLE指令检查表结构,示例如下:

    mysql> 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)       
  2. 检查表结构。

    使用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)    
  3. 观察当前正在执行的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。
  4. 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逻辑库是否一致。