---
title: "CREATE TABLE - OceanBase 数据库 V4.5.0 | OceanBase 文档中心"
description: "CREATE TABLE 描述 该语句用来在数据库中创建一张新表。 语法 CREATE [hint_options] [GLOBAL TEMPORARY] TABLE table_name (table_definition_list) [table_option_list] [partition_option] […"
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.5.0

# CREATE TABLE

更新时间：2026-03-15 13:50:15

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.5.0/zh-CN/700.reference/500.sql-reference/100.sql-syntax/300.common-tenant-of-oracle-mode/900.sql-statement-of-oracle-mode/100.ddl-of-oracle-mode/2400.create-table-of-oracle-mode.md)  

## 描述

该语句用来在数据库中创建一张新表。

## 语法

```sql
CREATE [hint_options] [GLOBAL TEMPORARY] TABLE table_name
      (table_definition_list) [table_option_list] [partition_option] [on_commit_option]
CREATE [GLOBAL TEMPORARY] TABLE table_name
      (table_definition_list) [table_option_list] [partition_option] [[MERGE_ENGINE = {delete_insert | partial_update}] table_column_group_option] [AS] select;

table_definition_list:
    table_definition [, table_definition ...]

table_definition:
      column_definition
     | [,
        | [CONSTRAINT [constraint_name]] { PRIMARY KEY|UNIQUE } (column_name) //在创建所有列后添加约束
        | [CONSTRAINT [constraint_name]] FOREIGN KEY (column_name, column_name ...) references_clause constraint_state
        | [CONSTRAINT [constraint_name]] CHECK(expression) constraint_state
       ]

column_definition_list:
    column_definition [, column_definition ...]

column_definition:
    column_name data_type
    [VISIBLE | INVISIBLE] [GENERATED BY DEFAULT AS IDENTITY | GENERATED ALWAYS AS IDENTITY]
    {
    [DEFAULT expression]
    [NULL | NOT NULL]
    [CONSTRAINT [constraint_name]] [ PRIMARY KEY|UNIQUE ]       //在创建列时添加约束
    [CONSTRAINT [constraint_name] CHECK(expression) constraint_state]
    [CONSTRAINT [constraint_name] references_clause]
    |
    [GENERATED ALWAYS] AS (expression) [VIRTUAL]
    [NULL | NOT NULL] [UNIQUE KEY] [[PRIMARY] KEY] [UNIQUE LOWER_KEY] [SKIP_INDEX(skip_index_option_list)]
    }

skip_index_option_list:
    skip_index_option [,skip_index_option ...]

skip_index_option:
    MIN_MAX
    | SUM

references_clause:
     REFERENCES table_name [ (column_name, column_name ...) ] [ON DELETE {SET NULL | CASCADE}]

constraint_state:
    [RELY | NORELY] [USING INDEX index_option_list] [ENABLE | DISABLE] [VALIDATE | NOVALIDATE]

index_option_list:
    index_option [ index_option ...]

index_option:
      [GLOBAL | LOCAL]
    | block_size
    | compression
    | STORING(column_name_list)

table_option_list:
    table_option [ table_option ...]

table_option:
      TABLEGROUP = tablegroup_name
    | block_size
    | compression
    | ENABLE ROW MOVEMENT
    | DISABLE ROW MOVEMENT
    | physical_attribute
    | parallel_clause
    | DUPLICATE_SCOPE [=] 'none|cluster'
    | TABLE_MODE [=] 'table_mode_value'
    | enable_macro_block_bloom_filter [=] {True | False}
    | DYNAMIC_PARTITION_POLICY [=] (dynamic_partition_policy_list)
    | MICRO_BLOCK_FORMAT_VERSION [=] {1|2}
    | COLUMN_NAME_CASE_SENSITIVE [=] {True | False}

physical_attribute_list:
    physical_attribute [physical_attribute]

physical_attribute:
    PCTFREE [=] num
    | PCTUSED num
    | INITRANS num
    | MAXTRANS num
    | STORAGE(storage_option [storage_option] ...)
    | TABLESPACE tablespace

parallel_clause:
    {NOPARALLEL | PARALLEL integer}

table_mode_value:
    NORMAL
    | QUEUING
    | MODERATE
    | SUPER
    | EXTREME

dynamic_partition_policy_list:
    dynamic_partition_policy_option [, dynamic_partition_policy_option ...]

dynamic_partition_policy_option:
    ENABLE = {true | false}
    | TIME_UNIT = {'hour' | 'day' | 'week' | 'month' | 'year'}
    | PRECREATE_TIME = {'-1' | '0' | 'n {hour | day | week | month | year}'}
    | EXPIRE_TIME = {'-1' | '0' | 'n {hour | day | week | month | year}'}
    | TIME_ZONE = {'default' | 'time_zone'}
    | BIGINT_PRECISION = {'none' | 'us' | 'ms' | 's'}

compression:
    NOCOMPRESS
    | COMPRESS { BASIC | FOR OLTP | FOR QUERY [LOW | HIGH]  | FOR ARCHIVE [LOW | HIGH]}

storage_option:
    INITIAL num [K|M|G|T|P|E]
    | NEXT num [K|M|G|T|P|E]
    | MINEXTENTS num [K|M|G|T|P|E]
    | MAXEXTENTS num [K|M|G|T|P|E]

partition_option:
      PARTITION BY HASH(column_name_list)
      [subpartition_option] hash_partition_define
    | PARTITION BY RANGE (column_name_list)
      [subpartition_option] (range_partition_list)
    | PARTITION BY LIST (column_name_list)
      [subpartition_option] (list_partition_list)
    | PARTITION BY RANGE([column_name_list]) [SIZE('size_value')] [range_partition_list]
    | PARTITION BY RANGE (column_name) INTERVAL (expr)
        [subpartition_option]
        (range_partition)

/*模板化二级分区*/
subpartition_option:
      SUBPARTITION BY HASH (column_name_list) hash_subpartition_define
    | SUBPARTITION BY RANGE (column_name_list) SUBPARTITION TEMPLATE
      (range_subpartition_list)
    | SUBPARTITION BY LIST (column_name_list) SUBPARTITION TEMPLATE
      (list_subpartition_list)

/*非模板化二级分区*/
subpartition_option:
      SUBPARTITION BY HASH (column_name_list)
    | SUBPARTITION BY RANGE (column_name_list)
    | SUBPARTITION BY LIST (column_name_list)

subpartition_list:
      (hash_subpartition_list)
    | (range_subpartition_list)
    | (list_subpartition_list)

hash_partition_define:
      PARTITIONS partition_count [TABLESPACE tablespace] [compression]
    | (hash_partition_list)

hash_partition_list:
    hash_partition [, hash_partition ...]

hash_partition:
    partition [partition_name] [subpartition_list/*仅非模板化二级分区可定义*/]

hash_subpartition_define:
      SUBPARTITIONS subpartition_count
    | SUBPARTITION TEMPLATE (hash_subpartition_list)

hash_subpartition_list:
    hash_subpartition [, hash_subpartition ...]

hash_subpartition:
    subpartition [subpartition_name]

range_partition_list:
    range_partition [, range_partition ...]

range_partition:
    PARTITION [partition_name]
    VALUES LESS THAN {(expression_list) | (MAXVALUE)}
    [subpartition_list/*仅非模板化二级分区可定义*/]
    [ID = num] [physical_attribute_list] [compression]

range_subpartition_list:
    range_subpartition [, range_subpartition ...]

range_subpartition:
    SUBPARTITION subpartition_name
    VALUES LESS THAN {(expression_list) | MAXVALUE} [physical_attribute_list]

list_partition_list:
    list_partition [, list_partition] ...

list_partition:
    PARTITION [partition_name]
    VALUES (DEFAULT | expression_list)
    [subpartition_list /*仅非模板化二级分区可定义*/]
    [ID num] [physical_attribute_list] [compression]

list_subpartition_list:
    list_subpartition [, list_subpartition] ...

list_subpartition:
    SUBPARTITION [partition_name] VALUES (DEFAULT | expression_list) [physical_attribute_list]

expression_list:
    expression [, expression ...]

column_name_list:
    column_name [, column_name ...]

partition_name_list:
    partition_name [, partition_name ...]

partition_count | subpartition_count:
    INT_VALUE

on_commit_option:
    ON COMMIT DELETE ROWS
  | ON COMMIT PRESERVE ROWS

table_column_group_option：
    WITH COLUMN GROUP(all columns)
  | WITH COLUMN GROUP(each column)
  | WITH COLUMN GROUP(all columns, each column)

```

## 参数说明

| 参数 | 描述 |
| --- | --- |
| hint_options | 为可选项，指定 Hint 选项。支持手动指定旁路导入 Hint，包括 APPEND、DIRECT、NO_DIRECT。对应的 Hint 格式为 `//`，有关 CREATE TABLE AS SELECT 语句旁路导入数据的内容，参见 [全量旁路导入](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476081) 中的**使用 CREATE TABLE AS SELECT 语句旁路导入数据**章节。 |
| GLOBAL TEMPORARY | 将该表创建为临时表。 |
| DEFAULT expression | 指定列的默认值。`expression` 支持包含 Sequence 的函数表达式。   #### 注意    自增列不能设置默认值。 |
| BLOCK_SIZE | 指定表的微块大小。 |
| COMPRESSION | 指定存储格式 Flat/Encoding 以及压缩方法，对应如下：   - `nocompress`：使用 Flat 格式，不进行压缩。 - `compress [basic]`：使用 Flat 格式和 lz4_1.0 压缩方法。 - `compress for oltp`：使用 Flat 格式和 zstd_1.3.8 压缩方法。 - `query low` 或者 `query high`：使用 Encoding 格式和 lz4_1.0 压缩方法。 - `archive low` 或者 `archive high`：使用 Encoding 格式和 zstd_1.3.8 压缩方法。 |
| tablegroup_name | 指定表所属的 Table Group。 |
| FOREIGN KEY | 为创建的表指定外键。如果不指定外键名，则会使用表名 + `OBFK` + 创建时间命名。（例如，在 2021 年 8 月 1 日 00:00:00 为 `t1` 表创建的外键名称为 `t1_OBFK_1627747200000000`）。外键允许跨表交叉引用相关数据，当 `DELETE` 操作影响与子表相匹配行的父表中键值时，其结果取决于 `ON DELETE` 子句的引用操作：   - `CASCADE`：表示从父表中删除或更新行，并自动删除或更新子表中匹配的行。 - `SET NULL`：表示从父表中删除或更新行，并将子表中的外键列设置为 `NULL`。 |
| VISIBLE | 表示列可见，是默认的列状态。 |
| INVISIBLE | 表示列不可见，当将一个列设置为 `INVISIBLE` 后，在查询时该列将不会被默认显示。 |
| GENERATED BY DEFAULT AS IDENTITY \| GENERATED ALWAYS AS IDENTITY | 可选项，指定一个列为自增列。具体如下：   - `GENERATED BY DEFAULT AS IDENTITY`：表示在插入数据时，如果没有显式指定自增列的值，系统将使用默认的自增值。 - `GENERATED ALWAYS AS IDENTITY`：表示在插入数据时，必须使用自动生成的自增值，而不能显式指定自增列的值。    #### 注意    该列的数据类型必须是数值类型。 |
| physical_attribute | `PCTFREE`: 指定宏块保留空间百分比。其它属性 `STORAGE`、`TABLESPACE` 等仅为了语法兼容方便迁移，不生效。 |
| ENABLE/DISABLE ROW MOVEMENT | 是否允许在不同分区间移动以进行分区键更新。 |
| ON COMMIT DELETE ROWS | 事务级临时表，提交时删除数据。 |
| ON COMMIT PRESERVE ROWS | 会话级临时表，会话结束时删除数据。 |
| parallel_clause | 指定表级别的并行度：   - `NOPARALLEL`：并行度为 1，为默认配置。 - `PARALLEL integer`：指定并行度，`integer` 取值大于等于 `1`。    #### 注意    当指定并行度时，优先级关系如下：通过 Hint 指定的并行度 > 通过 `ALTER SESSION` 指定的并行度 > 表级别的并行度。 |
| DUPLICATE_SCOPE | 指定复制表的属性，取值如下：   - `none`：表示该表是一个普通表，为默认值。 `cluster`：表示该表是一个复制表，Leader 需要将事务复制到当前租户的所有 F（全能）副本及 R（只读）副本。  OceanBase 数据库目前仅支持 `cluster` 级别的复制表。 |
| MERGE_ENGINE = {delete_insert \| partial_update} | 可选项，用于指定表的更新模型，取值如下：   - `partial_update`：默认值，表示采用现有的更新模式不变。 - `delete_insert`: 表示采用 `merge on write` 的方式，将 `update` 转为 `delete` 和 `insert`，并且写全列。    #### 说明    参数 `MERGE_ENGINE` 在创建表时指定之后，其配置值将不可修改。 |
| table_column_group_option | 指定表列存选项。具体解释如下：   - `WITH COLUMN GROUP(all columns, each column)`：指定创建行存列存冗余的表。 - `WITH COLUMN GROUP(all columns)`：指定添加行存表。 - `WITH COLUMN GROUP(each column)`：指定创建列存表。 |
| SKIP_INDEX | 标识列的 Skip Index 属性。取值如下：   - `MIN_MAX`：是 Skip Index 中最通用的聚合数据类型，它会在索引节点粒度下存储被索引列的最大值、最小值和 Null Count。这种类型的数据可以加速下推的 Filter 和 `MIN/MAX` 聚合的下推。 - `SUM`：用于加速数值类型的 `SUM` 聚合的下推。    #### 注意    - JSON 和空间数据类型的列禁止创建 Skip Index。 - 生成列禁止创建 Skip Index。 |
| TABLE_MODE | 可选项，用于指定合并触发阈值与合并策略，即控制数据转储后的合并行为。取值的详细介绍可参见下文 [table_mode_value](#table_mode_value)。 |
| enable_macro_block_bloom_filter [=] {True \| False} | 用于指定是否持久化宏块级别 bloom filter。取值如下：   - `True`：开启持久化宏块级别 bloom filter。    - `False`：关闭持久化宏块级别 bloom filter。 |
| DYNAMIC_PARTITION_POLICY [=] (dynamic_partition_policy_list) | 指定表的动态分区管理属性，实现分区的自动创建和删除。`dynamic_partition_policy_list` 动态分区策略的可配置参数列表，各参数用英文逗号分隔，详细介绍可参见下文 [dynamic_partition_policy_option](#dynamic_partition_policy_option)。 |
| MICRO_BLOCK_FORMAT_VERSION | 可选项，用于指定表的微块存储格式版本号。具体如下：取值范围为 [1,+∞)   其中：    - `1`：表示和现有微块存储格式一致。   - `2`：表示启用新的 Flat 行存储格式。   - 其他取值：会提示非法报错。  #### 说明    该参数从 V4.4.1 版本开始引入。 |
| COLUMN_NAME_CASE_SENSITIVE [=] {True \| False} | 用于设置生成列的列名是否区分大小写。   其中：    - `True`：开启列名的大小写敏感性功能。   - `False`：关闭列名的大小写敏感性功能。       #### 说明        在 V4.5.0 之前的版本，默认大小写敏感，在 V4.5.0 及之后的版本默认大小写不敏感 |
| PARTITION BY RANGE([column_name_list]) [SIZE('size_value')] [range_partition_list] | 用于指定创建自动分区表。详细介绍可参见 [自动分区分裂](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004479315) 中的创建表时的自动分区语法。 |
| PARTITION BY RANGE (column_name) INTERVAL (expr) [subpartition_option] (range_partition) | 用于指定创建 Interval 类型分区表。详细介绍可参见 [创建分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476683) 中的创建 Interval 类型的分区表。 |

### table_mode_value

#### 说明

在以下列出的 `TABLE_MODE` 模式中，除了 `NORMAL` 模式之外，所有模式都代表 `QUEUING` 表。这种 `QUEUING` 表是最基本的表类型，并且随后列出的几种模式（除了 NORMAL 模式）代表了使用更加积极的合并策略。

- `NORMAL`：默认值，表示正常。在该模式下，数据转储后触发合并的概率极低。
 - `QUEUING`：在该模式下，数据转储后触发合并的概率低。
 - `MODERATE`：表示适度。在该模式下，数据转储后触发合并的概率为中等。
 - `SUPER`：表示超级。在该模式下，数据转储后触发合并的概率高。
 - `EXTREME`：表示极端。在该模式下，转储后触发合并的概率较高。

更多有关合并的信息，请参见 [自适应合并](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004478343)。

### dynamic_partition_policy_option

- `ENABLE = {true | false}`：可选项，表示是否启用动态分区管理。可修改，取值如下：

     - `true`：默认值，表示启用动态分区管理。
     - `false`：表示禁用动态分区管理。
 - `TIME_UNIT = {'hour' | 'day' | 'week' | 'month' | 'year'}`：必选项，表示分区的时间单位，即自动创建分区边界的间隔。不可修改，取值如下：

     - `hour`：按小时划分分区。
     - `day`：按天划分分区。
     - `week`：按周（星期）划分分区。
     - `month`：按月划分分区。
     - `year`：按年划分分区。
 - `PRECREATE_TIME = {'-1' | '0' | 'n {hour | day | week | month | year}'}`：可选项，表示预创建时间。调度一次动态分区管理，会预创建分区使得 **最大分区上界 > now() + precreate_time**。可修改，取值如下：

     - `-1`：默认值，表示不预创建分区。
     - `0`：表示仅预创建当前分区。
     - `n {hour | day | week | month | year}`：表示预创建对应时间跨度的分区。例如，`3 hour` 表示预创建 3 小时内的分区。  

  #### 说明

     - 需要预创建多个分区时，分区边界的间隔为 `TIME_UNIT`。
     - 首个预创建的分区边界为现存最大分区边界按 `TIME_UNIT` 向上取整。
 - `EXPIRE_TIME = {'-1' | '0' | 'n {hour | day | week | month | year}'}`：可选项，表示分区过期时间。调度一次动态分区管理，会删除所有 **分区上界 < now() - expire_time** 的过期分区。可修改，取值如下：

     - `-1`：默认值，表示分区永不过期。
     - `0`：表示除当前分区外，之前的所有分区均过期。
     - `n {hour | day | week | month | year}`：表示分区过期时间。例如，`1 day` 表示分区过期时间为 1 天。
 - `TIME_ZONE = {'default' | 'time_zone'}`：可选项，表示判断当前时间与时间类型（`date`、`timestamp` 类型）分区键大小时，依赖的时区信息。不可修改，取值如下：

     - `default`：默认值，表示不额外配置时区，使用租户时区。除上述类型外，其他类型 `time_zone` 字段必须为 `default`。
     - `time_zone`：表示自定义时区偏移值。例如，`+8:00` 等时区偏移值。
 - `BIGINT_PRECISION = {'none' | 'us' | 'ms' | 's'}`：可选项，表示 `number` 类型分区键的时间戳精度。不可修改，取值如下：

     - `none`：默认值，表示无精度（分区键不为 `number` 类型）。
     - `us`：微秒精度。
     - `ms`：毫秒精度。
     - `s`：秒精度。

更多有关创建动态分区表的信息，参见 [创建动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004479304)。

**示例如下：**

```sql
CREATE TABLE tbl2 (col1 INT, col2 TIMESTAMP)
    DYNAMIC_PARTITION_POLICY(
        ENABLE = true,
        TIME_UNIT = 'hour',
        PRECREATE_TIME = '3 hour',
        EXPIRE_TIME = '1 day',
        TIME_ZONE = '+8:00',
        BIGINT_PRECISION = 'none')
    PARTITION BY RANGE (col2)(
        PARTITION P0 VALUES LESS THAN (TIMESTAMP '2024-11-11 13:30:00')
        );

```

## 示例

- 创建表 `TEST_TBL1`。

  ```sql
  obclient> CREATE TABLE TEST_TBL1 (col1 INT PRIMARY KEY, col2 VARCHAR(50));

  ```
 - 创建表 `TEST_TBL2`，创建 Hash 分区，分区数为 `8` 的表。

  ```sql
  obclient> CREATE TABLE TEST_TBL2 (col1 INT PRIMARY KEY, col2 INT) PARTITION BY HASH(col1) PARTITIONS 8;

  ```
 - 创建表 `TEST_TBL3`，创建一级分区为 Range 分区，二级分区为 Hash 分区的表。

  ```sql
  obclient> CREATE TABLE TEST_TBL3 (col1 INT, col2 INT, col3 INT)
                   PARTITION BY RANGE(col1)
                   SUBPARTITION BY HASH(col2)  SUBPARTITIONS  5
                   (PARTITION p0 VALUES LESS THAN(0),
                    PARTITION p1 VALUES LESS THAN(100));

  ```
 - 创建表 `TEST_TBL4`，开启 Encoding 并使用 `zstd` 压缩，宏块保留空间为 `5%`。

  ```sql
  obclient> CREATE TABLE tbl6 (col1 INT, col2 INT, col3 VARCHAR(64))
                   COMPRESS FOR ARCHIVE
                   PCTFREE 5;

  ```
 - 创建一个事务级临时表 `TEST_TBL5`。

  ```sql
  obclient> CREATE GLOBAL TEMPORARY TABLE TEST_TBL5(col1 INT) ON COMMIT DELETE ROWS;

  ```
 - 创建一个带约束的表 `TEST_TBL6`。

  ```sql
  obclient> CREATE TABLE TEST_TBL6 (col1 INT, col2 INT, col3 INT,CONSTRAINT equal_check1 CHECK(col2 = col3 * 2) ENABLE VALIDATE);

  ```
 - 为表 `REF_T2` 指定外键，当 `DELETE` 操作影响与子表相匹配行的父表中键值时，执行 `SET NULL` 操作。

  ```sql
  obclient> CREATE TABLE REF_T1(c1 INT PRIMARY KEY,C2 INT);

  ```

  ```sql
  obclient> CREATE TABLE REF_T2(c1 INT PRIMARY KEY，C2 INT,FOREIGN KEY(c2) REFERENCES ref_t1(c1) ON DELETE SET NULL);

  ```
 - 创建非模板化的 Range + Range 二级分区表 `TEST_TBL7`。

  ```sql
  obclient> CREATE TABLE TEST_TBL7 (col1 INT, col2 INT, col3 INT)
                   PARTITION BY RANGE(col1)
                   SUBPARTITION BY RANGE(col2)
  (
    PARTITION p0 VALUES LESS THAN(100)
    (
      SUBPARTITION p0_r1 VALUES LESS THAN(2019),
      SUBPARTITION p0_r2 VALUES LESS THAN(2020),
      SUBPARTITION p0_r3 VALUES LESS THAN(2021)
    ),
    PARTITION p1 VALUES LESS THAN(200)
    (
      SUBPARTITION p1_r1 VALUES LESS THAN(2019),
      SUBPARTITION p1_r2 VALUES LESS THAN(2020),
      SUBPARTITION p1_r3 VALUES LESS THAN(2021)
    ),
    PARTITION p2 VALUES LESS THAN(300)
    (
      SUBPARTITION p2_r1 VALUES LESS THAN(2019),
      SUBPARTITION p2_r2 VALUES LESS THAN(2020),
      SUBPARTITION p2_r3 VALUES LESS THAN(2021)
    )
  );

  ```
 - 创建表 `TEST_TBL8` 的并行度为 `3`。

  ```sql
  obclient> CREATE TABLE TEST_TBL8(col1 INT PRIMARY KEY, col2 INT) PARALLEL 3;

  ```
 - 使用函数定义列的默认值。

  ```sql
  obclient> CREATE SEQUENCE SEQ_PERSONIPTVSEQ START WITH 1 MINVALUE 1 MAXVALUE 10 INCREMENT BY 2 NOCYCLE NOORDER CACHE 30;

  ```

  ```sql
  obclient> SELECT LPAD(SEQ_PERSONIPTVSEQ.NEXTVAL,18,TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS')) FROM DUAL;

  ```

  返回结果如下：

  ```sql
  +----------------------------------------------------------------------------+
  | LPAD(SEQ_PERSONIPTVSEQ.NEXTVAL,18,TO_CHAR(SYSDATE,'YYYY-MM-DDHH24:MI:SS')) |
  +----------------------------------------------------------------------------+
  | 2025-04-08 19:35:1                                                         |
  +----------------------------------------------------------------------------+

  ```

  ```sql
  obclient> CREATE TABLE FUNC_DEFAULT_TEST ( OID NUMBER(20,0) DEFAULT LPAD(SEQ_PERSONIPTVSEQ.NEXTVAL,18,TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS')) NOT NULL);

  ```
 - 创建 `cluster` 级别的复制表 `DUP_T1`。像普通表一样插入和读写复制表的数据。对于一个读请求，如果使用了 Proxy，读请求可能会路由到任意一个 OBServer 节点；如果直连 OBServer 节点，只要本地副本可读，就会在直连的 OBServer 节点上执行读请求。

  ```sql
  obclient> CREATE TABLE DUP_T1(c1 int) DUPLICATE_SCOPE = 'cluster';

  ```

  ```sql
  obclient> INSERT INTO DUP_T1 VALUES(1);

  ```

  ```sql
  obclient> SELECT * FROM DUP_T1;

  ```

  返回结果如下：

  ```sql
  +------+
  | C1   |
  +------+
  |    1 |
  +------+

  ```
 - 创建列存表 `TBL_CG`。

  ```sql
  obclient> CREATE TABLE tbl1_cg (col1 NUMBER PRIMARY KEY, col2 VARCHAR2(50)) WITH COLUMN GROUP(each column);

  ```
 - 创建表时标识列 Skip Index 属性。

  ```sql
  obclient> CREATE TABLE TEST_INDEX(
    col1 NUMBER SKIP_INDEX(MIN_MAX, SUM),
    col2 FLOAT SKIP_INDEX(MIN_MAX),
    col3 VARCHAR2(1024) SKIP_INDEX(MIN_MAX),
    col4 CHAR(10)
  );

  ```
 - 创建表 `TEST_TBL9`，它有一个整数类型的列 `col1`，并且指定该操作应用 5 个并行度来完成，指定了新表 `TEST_TBL8` 的数据内容将来源于表 `TEST_TBL8` 的查询结果。

  ```sql
  obclient> CREATE /*+ parallel(5) */ TABLE TEST_TBL9 (col1 NUMBER) AS SELECT col1 FROM TEST_TBL8;

  ```
 - 创建一个名为 `TEST_TBL10` 的表，列 `col1` 设置为自增列，并且指定为主键。

  ```sql
  obclient> CREATE TABLE TEST_TBL10 (
    col1 INT GENERATED BY DEFAULT AS IDENTITY,
    col2 VARCHAR2(50),
    PRIMARY KEY (col1)
  );

  ```
 - 创建开启持久化宏块级别 bloom filter 的表 `tb`。

  ```sql
  obclient> CREATE TABLE tb(c1 INT PRIMARY KEY, c2 INT) enable_macro_block_bloom_filter = True;

  ```
 - 创建表 `tb` 启用新的 Flat 行存储格式（版本 2）。

  ```sql
  obclient> CREATE TABLE tb(c1 INT PRIMARY KEY, c2 INT) micro_block_format_version = 2;

  ```

## Oracle 兼容模式 Global 临时表的使用限制

- Oracle 兼容模式下的临时表在多个业务场景下都有实际应用，具备基本的正确性/功能性保证。
 - 一般使用临时表的目的大多是做兼容，减少业务改造。当业务在有限场景，对临时表性能要求不高时可以使用。如果业务场景能够改成普通表，则改普通表更好。

### 性能和稳定性

- 临时表的 SQL 执行效率与普通表基本一样，无特别优势。
 - 临时表在事务结束/Session 断开时需要做额外的工作，即清理数据，会产生额外开销。
 - 临时表在登录时进行的检查和清理动作可能会对登录线程造成压力，导致登录时间变长，严重时导致无法登录。

### 创建临时表

当创建临时表时，默认会对建表语句进行改写：

- 新增 `SYS_SESSION_ID` 列作为主键。
 - 新增 `SYS_SESS_CREATE_TIME` 作为普通列。
 - 创建以 `SYS_SESSION_ID` 作为分区键的 Hash 分区表，分区个数为固定的 16 分区。

例如：

```sql
obclient> CREATE GLOBAL TEMPORARY TABLE TEST_TBL11(
  c1 INT,
  c2 INT,
  PRIMARY KEY(c1)
);

```

会被改写为如下形式。

```sql
obclient> CREATE GLOBAL TEMPORARY TABLE TEST_TBL11(
  SYS_SESSION_ID INT,
  SYS_SESS_CREATE_TIME INT,
  c1 INT,
  c2 INT,
  PRIMARY KEY(SYS_SESSION_ID, c1)
)
PARTITION BY HASH(SYS_SESSION_ID) PARTITIONS 16;

```

### 临时表 DML/查询语句

执行 `INSERT` 时，会默认将当前会话的 Session ID 和 Session 创建时间插入 `SYS_SESSION_ID` 列和 `SYS_SESS_CREATE_TIME`。

执行 `UPDATE`/`DELETE`/`SELECT` 时，通过 SQL 改写，默认会为包含临时表的语句添加过滤条件 “`SYS_SESSION_ID` = 当前会话 `session_id`”。通过这个条件，SQL 优化器可以进行分区裁剪并抽取查询范围。

### 临时表数据清理

- 对 `ON COMMIT DELETE ROWS` 选项的临时表（事务临时表，也是默认选项），在事务结束时，开启一个新事务，通过执行 `DELETE` 语句删除临时表数据。
 - 对 `ON COMMIT PRESERVE ROWS` 选项的临时表（会话临时表），在会话断开时，通过执行 `DELETE` 语句删除临时表数据。
 - 由于 Session ID 可能存在复用的情况，在 OceanBase 数据库 V3.2.4 BP4 和之前版本会在登录时对当前 Session ID 的数据进行检查，如果存在需要额外进行一次清理。
 - 由于 Session ID 不唯一进行的登录检查和清理，可能会导致故障（集群无法登录）。

### 临时表的路由

- 事务临时表（`ON COMMIT DELETE ROWS`） 事务内对临时表的访问只能路由给事务开启节点。
 - 会话临时表（`ON COMMIT PRESERVE ROWS`） 当 Session 访问过临时表后，OBServer 节点会通知 Proxy，让 Proxy 的后续请求只能发给当前 Session。

### 删除临时表

与普通表相同可以在 DML 执行的同时成功执行 `DROP`，临时表全部数据会被删除。这与 Oracle 的行为不同，Oracle 是等待所有 Session 不持有临时表资源之后，才能 `DROP`。

### 交叉功能的支持情况

| 功能 | V3.2.4 BP4 和之前版本是否支持 | V3.2.4 BP5 和 V3.2.x 后续版本是否支持 | V4.2.0 版本是否支持 |
| --- | --- | --- | --- |
| 不同 Session 共享计划 | No | No | Yes |
| 登录无需触发检查和清理 | No | Yes | Yes |
| `MERGE INTO` 语句 | No | No | Yes |

### 严重问题的规避手段

### 无法登录

1. 停止临时表相关业务，将临时表删除或做一次合并，一般可以自行恢复，如果仍然无法恢复，则进行第 2 步。
 2. 重启无法登录的机器。

### 无法重用计划导致 PL Cache 膨胀

例如 PL 定义中包含临时表的语句：

```sql
obclient> CREATE OR REPLACE PROCEDURE PRO_1
AS
  var1 VARCHAR2(100);
BEGIN
  -- 使用动态 SQL 创建临时表
  EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE temp_table (
    col1 VARCHAR2(100)
  ) ON COMMIT DROP';

  -- 动态插入数据
  EXECUTE IMMEDIATE 'INSERT INTO temp_table VALUES (''xxx'')';

  -- 动态查询
  EXECUTE IMMEDIATE 'SELECT col1 FROM temp_table WHERE ROWNUM = 1' INTO var1;

  DBMS_OUTPUT.PUT_LINE(var1);
END PRO_1;
/

```

由于不同 Session 对临时表访问无法共享计划，每个 Session 都需要编译一次这个 Procedure `PRO_1` 生成对应的 Cache，可能导致稳定性问题。将临时表 SQL 改为动态 SQL 可以绕过这个问题。

### 故障情况数据未清理

故障情况可能导致数据残留，目前无自动清理办法，一般不影响使用。如果残留数据过多，可以通过 `DROP` 临时表，再重建解决。

## Oracle 租户下的只读和读写表

在 Oracle 租户下，您可以使用 `CREATE TABLE` 创建 `READ ONLY` 和 `READ WRITE` 类型的表。您也可以使用 `ALTER TABLE` 语句更改表的读写属性。

#### 注意

拥有 `SUPER` 权限的用户无法成功执行相关操作，建议使用普通用户。

**操作步骤：**

1. 创建普通用户：

   ```sql
   CREATE USER test1 IDENTIFIED BY "12345";

   ```
 2. 授予用户连接和建表权限：

   ```sql
   GRANT CREATE SESSION TO test1;
   GRANT CREATE TABLE TO test1;

   ```
 3. 使用普通用户连接 OceanBase 数据库：

   ```bash
   obclient -hxxx.xx.xxx.xxx -P2881 -utest1@oracle001  -A

   ```
 4. 创建只读表：

   ```sql
   CREATE TABLE tb_readonly1(id INT) READ ONLY;

   ```
 5. 尝试向只读表插入数据（预期失败）：

   ```sql
   INSERT INTO tb_readonly1 VALUES (1);
   -- 预期报错：ORA-00600: internal error code, arguments: -5235, The table 'TEST1.TB_READONLY1' is read only so it cannot execute this statement

   ```
 6. 创建读写表：

   ```sql
   CREATE TABLE tb_readwrite1(id INT) READ WRITE;

   ```
 7. 向读写表插入数据（预期成功）：

   ```sql
   INSERT INTO tb_readwrite1 VALUES (99),(98);
   -- 预期结果：Query OK, 2 rows affected (0.002 sec)
   --             Records: 2  Duplicates: 0  Warnings: 0

   ```
 8. 将读写表转换为只读表：

   ```sql
   ALTER TABLE tb_readwrite1 READ ONLY;

   ```
 9. 尝试向转换后的只读表插入数据（预期失败）：

   ```sql
   INSERT INTO tb_readwrite1 VALUES (96),(97);
   -- 预期报错：ORA-00600: internal error code, arguments: -5235, The table 'TEST1.TB_READWRITE1' is read only so it cannot execute this statement

   ```

## 相关文档

- [更改表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476667)
 - [创建表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476676)
 - [清空表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476670)
 - [删除表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004476669)

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
