当 OceanBase 集群中存在异常的服务器节点(比如宕机)时,创建 DDL 的操作可能会失败,本文主要描述在这种场景下不同 DDL 创建的行为差异。
适用版本
OceanBase 数据库 V2.x、V3.x 版本。
集群节点不可用时的 DDL 限制
当 OceanBase 集群存在故障(inactive)节点时,DDL 操作可能会因为无法创建出足够的副本而失败。变量 ob_create_table_strict_mode 可以控制在副本数量不足时 CREATE TABLE 是否成功。
ob_create_table_strict_mode = 1表示:严格按照 Locality 建立副本,任何副本建立失败,则建表失败。-4624, machine resource is not enough to hold a new unitob_create_table_strict_mode = 0表示:全类型副本至少有 1 个,Paxos 成员组副本达到多数,则建表成功。 不同的 DDL 类型对副本数的要求不同,还存在新表(节点故障后创建的表)与老表(节点故障前创建的表)的行为差异行,以下测试结果来自 OceanBase V3.2.4 版本。

对于老表创建本地索引,会话不返回,process 状态一直处于 ACTIVE 状态。
对于 drop column 操作,只要表缺副本,均无法成功。
-4694, check drop column failed创建表和创建全局索引的成功取决于
ob_create_table_strict_mode参数。
详细测试示例
测试版本 OceanBase 数据库 V3.2.4 版本。
将变量 ob_create_table_strict_mode 设置为 false 执行测试
删除已存在的新旧表。
obclient > drop table old_t_single purge;obclient > drop table new_t_single purge;obclient > drop table old_t_part purge;obclient > drop table new_t_part purge;创建非分区老表和分区老表。
obclient > create table old_t_single (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10));obclient > create table old_t_part (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6;向非分区老表和分区老表插入数据,执行如下存储过程。
obclient > begin for i in 1..1000 loop insert into old_t_single values(i ,'AAA'||i ,'BBB'||i ,'CCC'||i,'DDD'||i) ; end loop; end; /提交插入数据。
obclient > commit;obclient > begin for i in 1..10000 loop insert into old_t_part values(i ,'AAA'||i ,'BBB'||i ,'CCC'i,'DDD'||i) ; end loop; end; /提交插入数据。
obclient > commit;在非分区老表和分区老表上创建本地索引。
obclient > create index old_i_single_1 on old_t_single(col1) local;obclient > create index old_i_part_1 on old_t_part(col1) local ;在非分区老表和分区老表上创建全局分区索引。
obclient > create index old_i_single_2 on old_t_single(id,col2) global partition by hash(id) partitions 6;obclient > create index old_i_part_2 on old_t_part(id,col2) global partition by hash(id) partitions 6;查询 ob_create_table_strict_mode 参数。
obclient [OBORACLE]> show variables like '%create_table%';输出结果如下。
+-----------------------------+-------+ | VARIABLE_NAME | VALUE | +-----------------------------+-------+ | ob_create_table_strict_mode | OFF | +-----------------------------+-------+ 1 row in set (0.004 sec)查询 rootserver 服务的状态。
obclient [oceanbase]> select svr_ip,svr_port,id,zone,with_rootserver,status from oceanbase.__all_server;输出结果如下。
+-------------+----------+----+-------+-----------------+----------+ | svr_ip | svr_port | id | zone | with_rootserver | status | +-------------+----------+----+-------+-----------------+----------+ | xx.xx.xx.xx | 2882 | 1 | zone1 | 1 | active | | xx.xx.xx.xx | 2882 | 2 | zone2 | 0 | active | | xx.xx.xx.xx | 2882 | 3 | zone3 | 0 | inactive | +-------------+----------+----+-------+-----------------+----------+ 3 rows in set (0.001 sec)创建非分区新表和分区新表。
obclient [OBORACLE]> create table new_t_single (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10));obclient [OBORACLE]> create table new_t_part (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6;obclient [OBORACLE]> create table old_t_single2 (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10));obclient [OBORACLE]> create table old_t_part2 (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6;向非分区新表和分区新表插入数据,执行如下存储过程。
obclient [OBORACLE]> begin for i in 1..1000 loop insert into new_t_single values(i ,'AAA'||i ,'BBB'||i ,'CCC'||i,'DDD'||i) ; end loop; end; /提交插入数据。
obclient [OBORACLE]> commit;obclient [OBORACLE]> begin for i in 1..10000 loop insert into new_t_part values(i ,'AAA'||i ,'BBB'||i ,'CCC'||i,'DDD'||i) ; end loop; end; /obclient [oceanbase]> commit;删除非分区新表和分区新表。
obclient [OBORACLE]> drop table new_t_single;obclient [OBORACLE]> drop table new_t_part;创建 local 索引 old 字段。
obclient [oceanbase]> create index old_i_single_3 on old_t_single(col3) local;获取会话所属的用户信息。
obclient [oceanbase]> select * from oceanbase.__all_virtual_processlist where tenant='t_oracle' and user='OBORACLE' \G;输出结果如下。
*************************** 1. row *************************** id: 3221836921 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:36386 db: OBORACLE command: Query sql_id: 61733DA56062021BD32B5E3FBECA7F49 time: 142 state: ACTIVE info: create index old_i_single_1 on old_t_single(col1) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8865 ssl_cipher: NULL trace_id: YB42AC100120-0005FE1ABA799DE9-0-0 trans_state: total_time: 142 retry_cnt: 0 retry_info: 0 action: module: client_info: 1 row in set (0.035 sec)创建非分区新表和分区新表本地索引。
obclient [OBORACLE]> create index new_i_single_3 on new_t_single(col3) local; Query OK, 0 rows affected (0.784 sec)obclient [OBORACLE]> create index new_i_part_3 on new_t_part(col3) local ; Query OK, 0 rows affected (0.994 sec)创建全局索引在非分区老表和分区老表 old 原有字段。
obclient [OBORACLE]> create index old_i_single_4 on old_t_single(id,col4) global partition by hash(id) partitions 6; Query OK, 0 rows affected (1.425 sec)obclient [OBORACLE]> create index old_i_part_4 on old_t_part(id,col4) global partition by hash(id) partitions 6; Query OK, 0 rows affected (1.853 sec)创建全局索引在非分区老表和分区老表 new 新建字段。
obclient [OBORACLE]> create index new_i_single_4 on old_t_single(id,col4) global partition by hash(id) partitions 6; Query OK, 0 rows affected (1.571 sec)obclient [OBORACLE]> create index new_i_part_4 on old_t_part(id,col4) global partition by hash(id) partitions 6; Query OK, 0 rows affected (2.491 sec)删除本地索引 old 字段-原有。
obclient [OBORACLE]> drop index old_i_single_1; Query OK, 0 rows affected (0.047 sec)obclient [OBORACLE]> drop index old_i_part_1; Query OK, 0 rows affected (0.087 sec)删除全局索引 old 字段-原有。
obclient [OBORACLE]> drop index old_i_single_2; Query OK, 0 rows affected (0.056 sec)obclient [OBORACLE]> drop index old_i_part_2; Query OK, 0 rows affected (0.067 sec)删除本地索引 old 字段-新建。
无法新建本地索引。
obclient [OBORACLE]> drop index new_i_single_3; Query OK, 0 rows affected (0.061 sec)obclient [OBORACLE]> drop index new_i_part_3; Query OK, 0 rows affected (0.039 sec)obclient [OBORACLE]> drop index new_i_single_4;obclient [OBORACLE]> drop index new_i_part_4;删除全局索引 old 字段-新建。
obclient [OBORACLE]> drop index old_i_single_4; Query OK, 0 rows affected (0.059 sec)obclient [OBORACLE]> drop index old_i_part_4; Query OK, 0 rows affected (0.043 sec)增加列。
obclient [OBORACLE]> alter table old_t_single add (col5 varchar2(10),col6 varchar2(10)); Query OK, 0 rows affected (0.082 sec)obclient [OBORACLE]> alter table old_t_part add (col5 varchar2(20),col6 varchar2(10)) ; Query OK, 0 rows affected (0.047 sec)obclient [OBORACLE]> alter table new_t_single add (col5 varchar2(10),col6 varchar2(10)); Query OK, 0 rows affected (0.089 sec)obclient [OBORACLE]> alter table new_t_part add (col5 varchar2(20),col6 varchar2(10)) ; Query OK, 0 rows affected (0.061 sec)创建 local 索引 new 字段。
obclient [OBORACLE]> create index old_i_single_5 on old_t_single(col5) local;获取会话所属的用户信息。
obclient [oceanbase]> select * from oceanbase.__all_virtual_processlist where tenant='t_oracle' and user='OBORACLE' \G;输出结果如下。
*************************** 1. row *************************** id: 3221718630 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:40588 db: OBORACLE command: Query sql_id: E16FE7B9FF3E882924477374F2CB8D54 time: 19 state: ACTIVE info: create index old_i_single_5 on old_t_single(col5) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8951 ssl_cipher: NULL trace_id: YB42AC10011F-0005FE1ABA085225-0-0 trans_state: total_time: 19 retry_cnt: 0 retry_info: 0 action: module: client_info:创建非分区新表和分区新表本地索引。
obclient [OBORACLE]> create index new_i_single_5 on new_t_single(col5) local; Query OK, 0 rows affected (0.569 sec)obclient [OBORACLE]> create index new_i_part_5 on new_t_part(col5) local; Query OK, 0 rows affected (0.985 sec)创建全局索引 new 字段。
obclient [OBORACLE]> create index old_i_single_6 on old_t_single(id,col6) global partition by hash(id) partitions 6; Query OK, 0 rows affected (1.371 sec)obclient [OBORACLE]> create index old_i_part_6 on old_t_part(id,col6) global partition by hash(id) partitions 6; Query OK, 0 rows affected (2.095 sec)obclient [OBORACLE]> create index new_i_single_6 on new_t_single(id,col6) global partition by hash(id) partitions 6; Query OK, 0 rows affected (2.067 sec)obclient [OBORACLE]> create index new_i_part_6 on new_t_part(id,col6) global partition by hash(id) partitions 6; Query OK, 0 rows affected (2.083 sec)删除本地索引 new 字段-新建。
无法创建本地索引。
obclient [OBORACLE]> drop index new_i_single_5; Query OK, 0 rows affected (0.126 sec)obclient [OBORACLE]> drop index new_i_part_5; Query OK, 0 rows affected (0.114 sec)删除全局索引 new 字段-新建。
obclient [OBORACLE]> drop index old_i_single_6; Query OK, 0 rows affected (0.073 sec)obclient [OBORACLE]> drop index old_i_part_6; Query OK, 0 rows affected (0.060 sec)obclient [OBORACLE]> drop index new_i_single_6; Query OK, 0 rows affected (0.079 sec)obclient [OBORACLE]> drop index new_i_part_6; Query OK, 0 rows affected (0.051 sec)删除列 old 列。
obclient [OBORACLE]> alter table old_t_single drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table old_t_part drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table new_t_single drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table new_t_part drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failed删除列 new 列。
obclient [OBORACLE]> alter table old_t_single drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table old_t_part drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table new_t_single drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table new_t_part drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failed
将变量 ob_create_table_strict_mode 设置为 true 执行测试
删除已存在的新旧表。
obclient [OBORACLE]> drop table old_t_single purge;obclient [OBORACLE]> drop table new_t_single purge;obclient [OBORACLE]> drop table old_t_part purge;obclient [OBORACLE]> drop table new_t_part purge;创建非分区老表和分区老表。
obclient [OBORACLE]> create table old_t_single (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10));obclient [OBORACLE]> create table old_t_part (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6;向非分区老表和分区老表插入数据,执行如下存储过程。
obclient [OBORACLE]> begin for i in 1..1000 loop insert into old_t_single values(i ,'AAA'||i ,'BBB'||i ,'CCC'||i,'DDD'||i) ; end loop; end; /提交插入数据。
obclient [OBORACLE]> commit;obclient [OBORACLE]> begin for i in 1..10000 loop insert into old_t_part values(i ,'AAA'||i ,'BBB'||i ,'CCC'||i,'DDD'||i) ; end loop; end; /提交插入数据。
obclient [OBORACLE]> commit;在非分区老表和分区老表上创建本地索引。
obclient [OBORACLE]> create index old_i_single_1 on old_t_single(col1) local;obclient [OBORACLE]> create index old_i_part_1 on old_t_part(col1) local;obclient [OBORACLE]> create index old_i_single_2 on old_t_single(id,col2) global partition by hash(id) partitions 6;obclient [OBORACLE]> create index old_i_part_2 on old_t_part(id,col2) global partition by hash(id) partitions 6;obclient [OBORACLE]> create table old_t_single2 (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10));obclient [OBORACLE]> create table old_t_part2 (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6;设置 ob_create_table_strict_mode 参数。
obclient [OBORACLE]> set ob_create_table_strict_mode=ON; Query OK, 0 rows affected (0.001 sec)查询 ob_create_table_strict_mode 参数。
obclient [OBORACLE]> show variables like '%create_table%';输出结果如下。
+-----------------------------+-------+ | VARIABLE_NAME | VALUE | +-----------------------------+-------+ | ob_create_table_strict_mode | ON | +-----------------------------+-------+ 1 row in set (0.002 sec)查询 rootserver 服务的状态。
obclient [oceanbase]> select svr_ip,svr_port,id,zone,with_rootserver,status from __all_server;输出结果如下。
+-------------+----------+----+-------+-----------------+----------+ | svr_ip | svr_port | id | zone | with_rootserver | status | +-------------+----------+----+-------+-----------------+----------+ | xx.xx.xx.xx | 2882 | 1 | zone1 | 1 | active | | xx.xx.xx.xx| 2882 | 2 | zone2 | 0 | active | | xx.xx.xx.xx | 2882 | 3 | zone3 | 0 | inactive | +-------------+----------+----+-------+-----------------+----------+ 3 rows in set (0.001 sec)创建非分区新表和分区新表。
obclient [OBORACLE]> create table new_t_single (id number primary key ,col1 varchar2(10) ,col2 varchar(10) ,col3 varchar2(10) ,col4 varchar(10)); ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unitobclient [OBORACLE]> create table new_t_part (id number primary key ,col1 varchar2(10) ,col2 varchar(10),col3 varchar2(10) ,col4 varchar(10) ) partition by hash(id) partitions 6; ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unit删除非分区老表和分区老表。
obclient [OBORACLE]> drop table old_t_single2; Query OK, 0 rows affected (0.039 sec)obclient [OBORACLE]> drop table old_t_part2; Query OK, 0 rows affected (0.039 sec)创建非分区 local 索引 old 字段。
obclient [OBORACLE]> create index old_i_single_3 on old_t_single(col3) local ; Query OK, 0 rows affected (0.089 sec)获取会话所属的用户信息。
obclient [oceanbase]> select * from oceanbase.__all_virtual_processlist where tenant='t_oracle' and user='OBORACLE' \G;输出结果如下。
*************************** 1. row *************************** id: 3221718630 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:40588 db: OBORACLE command: Query sql_id: D41D8CD98F00B204E9800998ECF8427E time: 5 state: ACTIVE info: create index old_i_single_3 on old_t_single(col3) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8951 ssl_cipher: NULL trace_id: YB42AC10011F-0005FE1ABA085279-0-0 trans_state: otal_time: 5 retry_cnt: 0 retry_info: 0 action: module: client_info:创建分区 local 索引 old 字段。
obclient [oceanbase]> create index old_i_part_3 on old_t_part(col3) local ;获取会话所属的用户信息。
obclient [oceanbase]> select * from __all_virtual_processlist where tenant='t_oracle' and user='OBORACLE' \G;输出结果如下。
*************************** 1. row *************************** id: 3221718630 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:40588 db: OBORACLE command: Query sql_id: D41D8CD98F00B204E9800998ECF8427E time: 3 state: ACTIVE info: create index old_i_part_3 on old_t_part(col3) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8951 ssl_cipher: NULL trace_id: YB42AC10011F-0005FE1ABA08527A-0-0 trans_state: total_time: 3 retry_cnt: 0 retry_info: 0 action: module: client_info:创建全局索引 old 字段。
obclient [OBORACLE]> create index old_i_single_4 on old_t_single(id,col4) global partition by hash(id) partitions 6; ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unitobclient [OBORACLE]> create index old_i_part_4 on old_t_part(id,col4) global partition by hash(id) partitions 6; ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unit删除本地索引 old字段-原有。
obclient [OBORACLE]> drop index old_i_single_1; Query OK, 0 rows affected (0.047 sec)obclient [OBORACLE]> drop index old_i_part_1; Query OK, 0 rows affected (0.087 sec)删除全局索引 old 字段-原有。
obclient [OBORACLE]> drop index old_i_single_2; Query OK, 0 rows affected (0.040 sec)obclient [OBORACLE]> drop index old_i_part_2; Query OK, 0 rows affected (0.042 sec)删除本地索引 old 字段-新建。
无法新建本地索引。
删除全局索引 old 字段-新建。
无法新建全局索引。
增加列。
obclient [OBORACLE]> alter table old_t_single add (col5 varchar2(10),col6 varchar2(10)); Query OK, 0 rows affected (0.082 sec)obclient [OBORACLE]> alter table old_t_part add (col5 varchar2(20),col6 varchar2(10)) ; Query OK, 0 rows affected (0.047 sec)创建非分区 local 索引 new 字段。
obclient [OBORACLE]>create index old_i_single_5 on old_t_single(col5) local;获取会话所属的用户信息。
obclient [oceanbase]> select * from oceanbase.__all_virtual_processlist where tenant='t_oracle' and user='OBORACLE' \G;输出结果如下。
*************************** 1. row *************************** id: 3221718630 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:40588 db: OBORACLE command: Query sql_id: D41D8CD98F00B204E9800998ECF8427E time: 7 state: ACTIVE info: create index old_i_single_5 on old_t_single(col5) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8951 ssl_cipher: NULL trace_id: YB42AC10011F-0005FE1ABA085283-0-0 trans_state: total_time: 7 retry_cnt: 0 retry_info: 0 action: module: client_info:创建分区 local 索引 new 字段。
obclient [oceanbase]> create index old_i_part_5 on old_t_part(col5) local;输出结果如下。
*************************** 1. row *************************** id: 3221718630 user: OBORACLE tenant: t_oracle host: 172.xx.x.xx:40588 db: OBORACLE command: Query sql_id: D41D8CD98F00B204E9800998ECF8427E time: 6 state: ACTIVE info: create index old_i_part_5 on old_t_part(col5) local svr_ip: 172.xx.x.xx svr_port: 2882 sql_port: 2881 proxy_sessid: 12398411006995530173 master_sessid: NULL user_client_ip: 172.xx.x.xx user_host: % trans_id: 0 thread_id: 8951 ssl_cipher: NULL trace_id: YB42AC10011F-0005FE1ABA085284-0-0 trans_state: total_time: 6 retry_cnt: 0 retry_info: 0 action: module: client_info:创建全局索引 new 字段。
obclient [OBORACLE]> create index old_i_single_6 on old_t_single(id,col6) global partition by hash(id) partitions 6; ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unitobclient [OBORACLE]> create index old_i_part_6 on old_t_part(id,col6) global partition by hash(id) partitions 6; ORA-00600: internal error code, arguments: -4624, machine resource is not enough to hold a new unit删除本地索引 new 字段-新建。
无法创建本地索引。
删除全局索引 new字段-新建。
无法创建全局索引。
删除列 OLD 列。
obclient [OBORACLE]> alter table old_t_single drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table old_t_part drop (col4); ORA-00600: internal error code, arguments: -4694, check drop column failed删除列 new 列。
obclient [OBORACLE]> alter table old_t_single drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failedobclient [OBORACLE]> alter table old_t_part drop (col6); ORA-00600: internal error code, arguments: -4694, check drop column failed