decimal 增加列长 offline ddl判定

前言

offline ddl 会锁表并且执行时间通常很长,对业务影响较大,需要明确与online ddl区分开,一般查下文档后还需要再次验证下结论是否准确,近期发现增加列长 DECIMAL 时而是online ddl时而是offline ddl 的现象

结论

结论放前面 :decimal 类型特殊,增加列长操作超过阈值就是 offline ddl操作,比如从 3->9 就是 online ddl,3->10就是 offline ddl操作,修改小数位为 offline ddl 操作

环境

版本:OceanBase 4.3.5.5

模式:mysql

测试

create table test1 (c1 int primary key,c2 DECIMAL(6,2));
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
alter table test1 modify c2 DECIMAL(7,2);
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
alter table test1 modify c2 DECIMAL(19,2);
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
alter table test1 modify c2 DECIMAL(19,3);
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
obclient(dc@(none))[dc]> create table test1 (c1 int primary key,c2 DECIMAL(6,2));
Query OK, 0 rows affected (0.213 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
+----------+
| table_id |
+----------+
|  1082169 |
+----------+
1 row in set (0.223 sec)

obclient(dc@(none))[dc]> alter table test1 modify c2 DECIMAL(7,2);
Query OK, 0 rows affected (0.180 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
+----------+
| table_id |
+----------+
|  1082169 |
+----------+
1 row in set (0.018 sec)

obclient(dc@(none))[dc]> alter table test1 modify c2 DECIMAL(19,2);
Query OK, 0 rows affected (1.040 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
+----------+
| table_id |
+----------+
|  1082170 |
+----------+
1 row in set (0.018 sec)

obclient(dc@(none))[dc]> alter table test1 modify c2 DECIMAL(19,3);

Query OK, 0 rows affected (0.939 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='test1';
+----------+
| table_id |
+----------+
|  1082171 |
+----------+
1 row in set (0.018 sec)

如上,c2列从 DECIMAL(6,2) → DECIMAL(7,2),是online ddl,DECIMAL(7,2) → DECIMAL(19,2)是offline ddl

找了下435文档,增加列长是online ddl,跟测试结果冲突

分支 条件 结果
第一个 if 源列类型为:number、bit、char、varchar、varbinary、text、blob、timestamp、datetime、任意整数类型、json 在线:不设置 is_offline,保持可在线 DDL
else if 源列是 decimal int,且 scale (小数位)不变,且 精度对应的 decimal int 内部类型不变(get_decimalint_type(precision) 相同) 在线:同样不设置 is_offline
else 以上都不满足(例如 decimal int 改了 scale 或改了「精度档位」,或其他未列出的类型扩大长度) 离线:is_offline = true,需要离线 DDL

源码如上,decimal 比较特殊,超过阈值就是offline,比如从3->9就是online,3->10就是offline

create table dc_test1 (c1 int primary key,c2 DECIMAL(3,2));
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test1';
alter table dc_test1 modify c2 DECIMAL(9,2);
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test1';

create table dc_test2 (c1 int primary key,c2 DECIMAL(3,2));
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test2';
alter table dc_test2 modify c2 DECIMAL(10,2);
select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test2';
obclient(dc@(none))[dc]> create table dc_test1 (c1 int primary key,c2 DECIMAL(3,2));
Query OK, 0 rows affected (0.149 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test1';
+----------+
| table_id |
+----------+
|  1082176 |
+----------+
1 row in set (0.032 sec)

obclient(dc@(none))[dc]> alter table dc_test1 modify c2 DECIMAL(9,2);
Query OK, 0 rows affected (0.167 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test1';
+----------+
| table_id |
+----------+
|  1082176 |
+----------+
1 row in set (0.018 sec)

obclient(dc@(none))[dc]> 
obclient(dc@(none))[dc]> create table dc_test2 (c1 int primary key,c2 DECIMAL(3,2));
Query OK, 0 rows affected (0.142 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test2';
+----------+
| table_id |
+----------+
|  1082177 |
+----------+
1 row in set (0.018 sec)

obclient(dc@(none))[dc]> alter table dc_test2 modify c2 DECIMAL(10,2);

Query OK, 0 rows affected (1.001 sec)

obclient(dc@(none))[dc]> select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='dc_test2';
+----------+
| table_id |
+----------+
|  1082178 |
+----------+
1 row in set (0.017 sec)

官网的关于online ddl/offline ddl 文档这里描述没写清楚,由此建议所有应用生产的操作,务必先在测试环境验证!

其他

如何判断 DDL 操作为在线操作(Online DDL)

在 OceanBase 数据库中,DDL 操作的在线与离线状态对于业务运行的影响非常重要。本文将介绍如何判断 DDL 操作是否为 Online DDL,以及提供具体的操作步骤和注意事项。有些如列类型变更或混合 DDL 操作在执行前不确定是否为 Online DDL,建议先通过下述方式进行验证判断。

判断 DDL 为在线操作的方式

对于部分操作包含的范围比较广,并不能完全列举 DDL 操作为在线还是离线,建议用户如在有混合 DDL 操作的情况下,明确该操作是否为在线操作。

离线 DDL 的原理

OceanBase 的离线 DDL 操作采用 “重建表” 的方式。具体而言,离线 DDL 会新建一张临时的隐藏表(对用户不可见),然后将原表的数据迁移到新建的表中。完成数据迁移后,临时表会被重命名为原表的名称,并且旧表将被删除。因此,离线 DDL 操作完成后,table_id 会发生变化,需要注意在 DDL 执行期间不允许 DML 操作。

借助这一原理,可以判断某个 DDL 操作是否为在线 DDL。

判断方式

在 DDL 操作前后执行如下 SQL 语句查看 table_id 是否发生变化,如果没有变化,说明是 Online DDL,如果发生变化,则是 Offline DDL。

select distinct(table_id) from oceanbase.DBA_OB_TABLE_LOCATIONS where table_name='xxx';

判断步骤

通过下述判断步骤,判断 DDL 操作是否为 Online DDL。

  1. 创建一个用以验证的空表:
CREATE TABLE t10(a INT, b INT);
  1. 查看当前 table_id
SELECT distinct(table_id)
FROM oceanbase.DBA_OB_TABLE_LOCATIONS
WHERE table_name='t10';
  1. 执行预期的 DDL 操作:
ALTER TABLE t10 ADD c INT, ADD CONSTRAINT c_idx UNIQUE(c);
  1. 再次查看 table_id
SELECT distinct(table_id)
FROM oceanbase.DBA_OB_TABLE_LOCATIONS
WHERE table_name='t10';
  1. 如果步骤 2 和步骤 4 返回结果 table_id 相同,则说明这个 DDL 操作是在线的;如果 table_id 发生了变化,则对应的 DDL 操作是离线的。

说明:该判断方法对表操作和分区操作无效。

参考

435 offline ddl

原因为decimal底层存储格式不一样,底层存储格式不能兼容了,只能重定义换表了