#CREATE TABLE

# 通用描述

CREATE TABLE语句用于创建一个表对象,包括HEAP表、TAC表和LSC表:

  • HEAP Table:行存表,采用段页式结构。

  • TAC Table (Transaction Analytics Columnar Table) :列存表,采用段页式结构。

  • LSC Table (Large-scale Storage Columnar Table):列存表,通过列存结构组织数据。

YashanDB通过配置参数DEFAULT_TABLE_TYPE的值(HEAP/TAC/LSC)指定创建表对象时的默认表类型,该参数支持在线切换。同时,YashanDB支持通过ORGANIZATION语法在创建表对象时将其指定为任意的表类型。

分布式部署中不支持HEAP表,该语句还可以指定分布表(Sharded Table)和复制表(Duplicated Table)两种分布类型,默认创建分布表。

表类型在创建表对象时被指定,且创建后不可变更。

需注意的是,由于LSC表的对象存储属性,其所在表空间必须已挂载bucket(数据桶),而SYSTEM表空间默认无此设置,因此在系统用户(如SYS)下无法创建LSC表,除非通过ALTER TABLESPACE语句为SYSTEM表空间增加bucket。

Note

在企业生产环境中,一般并不建议在SYSTEM表空间和SYS用户下创建业务表,而应该为其创建单独的表空间和普通用户。

YashanDB中,通过CREATE USER语句创建的普通用户,其默认所属表空间已挂载bucket,可在该用户下创建LSC表。

# 语句定义

create table::=

syntax
CREATE GLOBAL PRIVATE TEMPORARY SHARDED DUPLICATED TABLE IF NOT EXISTS schema . table_name ( relation_properties ) table_properties lsc_table_properties row_movement_clause

relation_properties::=

syntax
column_definition out_of_line_constraint ,

out_of_line_constraint定义

column_definition::=

syntax
column dataType DEFAULT default_expr codec_expr inline_constraint

codec_expr::=

syntax
compression_clause encoding_clause

compression_clause::=

syntax
COMPRESSION compression_type HIGH MEDIUM LOW

compression_type::=

syntax
lz4

encoding_clause::=

syntax
ENCODING PLAIN RLE DICTIONARY ( RLE PLAIN , CARDINALITY ) BYTE-PACKED

inline_constraint定义

table_properties::=

syntax
organization_clause temp_table_attr_clause physical_attribute_clause table_partition_clause lob_clauses shard_distribute_clause logging_clause parallel_clause deferred_segment_creation cache_clause readonly_clause inmemory_clause table_compression nested_table_clauses

organization_clause::=

syntax
ORGANIZATION HEAP TAC LSC

temp_table_attr_clause::=

syntax
ON COMMIT DROP PRESERVE DEFINITION DELETE PRESERVE ROWS

physical_attribute_clause::=

syntax
TABLESPACE tablespace TABLESPACE SET tablespace_set PCTFREE integer PCTUSED integer INITRANS integer MAXTRANS integer storage_clause

storage_clause定义

size_clause/maxsize_clause

table_partition_clause::=

syntax
range_partitions list_partitions hash_partitions

range_partitions::=

syntax
PARTITION BY RANGE ( column , ) interval_clause ( PARTITION partname range_values_clause table_partition_description , )

interval_clause::=

syntax
INTERVEL ( expr ) STORE IN ( tablespace , )

range_values_clause::=

syntax
VALUES LESS THAN ( literal MAXVALUE , )

table_partition_description::=

syntax
TABLESPACE tablespace PCTFREE integer PCTUSED integer INITRANS integer MAXTRANS integer

list_partitions::=

syntax
PARTITION BY LIST ( column , ) ( PARTITION partname list_values_clause table_partition_description , )

list_values_clause::=

syntax
VALUES ( DEFAULT list_values )

list_values::=

syntax
literal NULL , ( literal NULL , ) ,

hash_partitions::=

syntax
PARTITION BY HASH ( column , ) individual_hash_partitions hash_partitions_by_quantity

individual_partition_clause::=

syntax
( PARTITION partname partition_storage_clause , )

partition_storage_clause::=

syntax
TABLESPACE tablespace

hash_partitions_by_quantity::=

syntax
PARTITIONS hash_partition_quantity STORE IN ( tablespace , ) OVERFLOW STORE IN ( tablespace , )

shard_distribute_clause::=

syntax
DISTRIBUTE BY HASH ( column_name , )

lob_clauses::=

syntax
lob_clause

lob_clause::=

syntax
LOB ( column , ) STORE AS BASICFILE SECUREFILE ( TABLESPACE space_name ENABLE DISABLE STORAGE IN ROW )

logging_clause::=

syntax
LOGGING NOLOGGING

parallel_clause::=

syntax
NOPARALLEL PARALLEL integer

deferred_segment_creation::=

syntax
SEGMENT CREATION IMMEDIATE DEFERRED

cache_clause::=

syntax
CACHE NOCACHE

readonly_clause::=

syntax
READONLY READWRITE

inmemory_clause::=

syntax
INMEMORY NO INMEMORY

table_compression::=

syntax
COMPRESS NOCOMPRESS

nested_table_clauses::=

syntax
nested_table_clause

nested_table_clause::=

syntax
NESTED TABLE nested_item COLUMN_VALUE LOCAL GLOBAL STORE AS storage_table ( nested_table_clause ) ( TABLESPACE tablespace_name )

lsc_table_properties::=

syntax
compression_clause table_sort_clause mcol_ttl_clause storage_table

table_sort_clause::=

syntax
ORDER BY ( column_name , ) NULLS FIRST LAST ASC DESC

mcol_ttl_clause::=

syntax
MCOL TTL timestamp

row_movement_clause::=

syntax
ENABLE DISABLE ROW MOVEMENT

# global temporary

该语句只作用于单机HEAP/TAC表,用于指定创建的表为全局临时表。全局临时表对数据库所有会话(Session)可见,但表中数据在各会话间隔离,即每个会话只能看到在本会话中插入的数据。

全局临时表被创建后将一直存在(除非被DROP),ON COMMIT DELETE | PRESERVE ROWS则定义了其数据在事务提交后是否保留,具体在temp_table_attr_clause中说明。

示例

CREATE GLOBAL TEMPORARY TABLE globaltemtable(c1 INT,c2 INT);

# private temporary

该语句只作用于单机HEAP/TAC表,用于指定创建的表为私有临时表。在某个会话中创建的私有临时表,其表结构及数据只对本会话可见。

私有临时表的数据在当前会话中一直保留,且不会在事务提交时被删除,ON COMMIT DROP | PRESERVE DEFINITION则定义了事务提交后是否DROP该表,具体在temp_table_attr_clause中说明。

私有临时表的名称必须为YAS$PTT_开头,而对于其他类型的表,其表名称则不允许以YAS$PTT_开头。

示例

CREATE PRIVATE TEMPORARY TABLE YAS$PTT_privatetemtable(c1 INT,c2 INT);

--如不以YAS$PTT_开头会返回错误
CREATE PRIVATE TEMPORARY TABLE privatetemtable(c1 INT,c2 INT);
YAS-02170 create a private temporary table with a name not matching 'YAS$PTT_' prefix

# sharded

该语句只在分布式部署中使用,表示创建一张分布表,在YashanDB分布式部署中,每一个数据节点为一个Shard,插入表中的数据将按照指定的规则(DISTRIBUTE BY可以定义这种规则,缺省则为哈希分配)被分配到各个Shard中。

SHARDED为YashanDB分布式数据库的默认建表方式,即CREATE TABLE=CREATE SHARDED TABLE。

示例(在建立了两个数据节点的分布式数据库中)

--创建area_shard表并插入记录
CREATE SHARDED TABLE area_shard
(area_no CHAR(2) NOT NULL,
area_name VARCHAR2(60),
DHQ VARCHAR2(20) DEFAULT 'ShenZhen' NOT NULL);
INSERT INTO area_shard VALUES ('10','华东','Shanghai');
INSERT INTO area_shard VALUES ('20','华西','Chengdu');
INSERT INTO area_shard VALUES ('30','华南','Guangzhou');
INSERT INTO area_shard VALUES ('40','华北','Beijing');
INSERT INTO area_shard VALUES ('50','华中','Wuhan');
COMMIT;
 
--节点1中查询到的数据
SELECT * FROM area_shard;
AREA_NO AREA_NAME        DHQ       
------ ---------------- -----------
0      华西           Chengdu     
0      华北           Beijing     
 
--节点2中查询到的数据
SELECT * FROM area_shard;
AREA_NO AREA_NAME        DHQ         
------- ---------------- ------------
10      华东           Shanghai      
30      华南           Guangzhou     
50      华中           Wuhan

# duplicated

该语句只在分布式部署中使用,表示创建一张复制表,插入表中的数据将被完全复制到各个数据节点中。

示例(在建立了两个数据节点的分布式数据库中)

--创建area_dupli表并插入记录
CREATE DUPLICATED TABLE area_dupli
(area_no CHAR(2) NOT NULL,
area_name VARCHAR2(60),
DHQ VARCHAR2(20) DEFAULT 'ShenZhen' NOT NULL);
INSERT INTO area_dupli VALUES ('10','华东','Shanghai');
INSERT INTO area_dupli VALUES ('20','华西','Chengdu');
INSERT INTO area_dupli VALUES ('30','华南','Guangzhou');
INSERT INTO area_dupli VALUES ('40','华北','Beijing');
INSERT INTO area_dupli VALUES ('50','华中','Wuhan');
COMMIT;
 
--节点1中查询到的数据
SELECT * FROM area_dupli;
AREA_NO AREA_NAME        DHQ            
------- ---------------- ----------------
10      华东           Shanghai         
20      华西           Chengdu          
30      华南           Guangzhou        
40      华北           Beijing          
50      华中           Wuhan            
 
--节点2中查询到的数据
SELECT * FROM area_dupli;
AREA_NO AREA_NAME        DHQ            
------- ---------------- ----------------
10      华东           Shanghai         
20      华西           Chengdu          
30      华南           Guangzhou        
40      华北           Beijing          
50      华中           Wuhan

# if not exists

该语句用于在CREATE表之前,先判断该表是否存在,省略则不会判断。若不省略,此时如果要创建的表存在,系统将不会报错,并且使用旧表,不会创建新的表。

示例

--创建已存在的表area时,不会报错,且新表未创建成功
CREATE TABLE IF NOT EXISTS area(c1 INT, c2 INT);

SELECT * FROM area WHERE area_no='01';
AREA_NO AREA_NAME        DHQ       
------- ---------------- ----------
01      华东           Shanghai    

# table_name

该语句用于指定创建的表的名称,不可省略,且需符合YashanDB的对象命名规范

如表名称里出现了.符号,表示该符号之前为用户名、之后为表名,此时必须拥有在指定用户名下创建表对象的权限。

# relation_properties

该语句用于指定创建的表的结构,包括列字段(Column)和约束(Constraint)。

# column_definition

该语句用于定义表的列字段项。

# column

列字段的名称,不可省略,且需符合YashanDB的对象命名规范

# datatype

指定列字段的数据类型。查看YashanDB的数据类型描述

其中,数据类型指定为LOB/JSON类型时,可通过lob_clauses子句指定其存储属性。

数据类型指定为Nested Table UDT类型时,必须通过nested_table_clauses子句创建嵌套表,且不能为临时表的列字段指定Nested Table UDT类型。

# default default_expr

列字段的缺省值。default_expr可以为字面量、运算式、函数等表达式。

# codec_expr

对于LSC表的列字段,使用本语句定义列字段的编码压缩属性,系统按此设置存储该列上的数据。 对于单机TAC表的列字段,使用本语句定义列字段的字典编码属性,系统按此设置存储该列上的数据。

# compression_clause

该语句用于对LSC表定义压缩属性。

compression_type

  • 压缩算法:采用当前流行的LZ4压缩算法。

  • 压缩级别:可指定按LOW、MEDIUM、HIGN三个级别进行压缩 ,未指定级别时,默认按LOW级别压缩。

YashanDB支持按表级别或列级别定义压缩属性,并提供如下配置参数用于设置系统默认的压缩属性:

  • COMPRESSION:是否进行数据压缩。
  • COMPRESSION_LEVEL:数据压缩的级别。

对于某一个列上的数据,基于表列级别定义的压缩属性与系统默认的压缩属性之间的优先关系如下:

  • 如果在该列上定义了压缩属性,则采用该列上的压缩属性进行数据存储。
  • 如果该列上没有定义,而在表上定义了压缩属性,则采用表上的压缩属性进行数据存储。
  • 如果该列和表上均未定义,则采用系统默认的压缩属性进行数据存储。

# encoding_clause

对于LSC表的列定义编码属性,指定按如下一种方式进行编码:

  • PLAIN编码:即不编码,按原始方式存储数据。
  • RLE编码:游程长度编码。
  • DICTIONARY(PLAIN):字典编码后的数据进行PLAIN编码。
  • DICTIONARY(RLE):字典编码后的数据进行RLE编码。
  • BYTE-PACKED:根据数据字节长度编码。

对于某一个列上的数据,是否应该编码和采用何种编码方式,与该列的数据类型和数据特点相关,如下为YashanDB对不同数据类型可适配的编码方式(✓表示适配,X表示不适配):

数据类型 PLAIN编码 RLE编码 字典编码 BYTE-PACKED编码
TINYINT/SMALLINT/大对象型 X X X
INT/BIGINT/FLOAT/DOUBLE/日期型 X
字符型 X X
NUMBER型 X X

其中,BOOLEAN类型数据由系统自动进行布尔编码存储,无需为其指定编码方式。长度大的CHAR字段采用字典编码对内存占用比较大,对于超过128字节的CHAR类型,请尽量不要选择字典编码。

示例

--创建LSC表,压缩指定列且对其字典编码存储
DROP TABLE IF EXISTS finance_info;
CREATE TABLE finance_info
(year CHAR(4) NOT NULL COMPRESSION lz4 HIGH ENCODING DICTIONARY(RLE),
month CHAR(2) NOT NULL,
branch CHAR(4),
revenue_total NUMBER(10,2),
cost_total NUMBER(10,2),
fee_total NUMBER(10,2)
);

对于TAC表的列定义字典编码属性,指定按DICTIONARY(PLAIN)方式进行编码,该属性仅支持数据类型为字符型的列使用。 同时TAC表的列使用该属性支持指定字典值上限,规格为[1,65535],缺省默认字典值上限为65535。

示例

--创建TAC表,对指定列字典编码存储且指定字典上限为100
DROP TABLE IF EXISTS finance_info;
CREATE TABLE finance_info
(year CHAR(4) NOT NULL ENCODING DICTIONARY(PLAIN, 100),
month CHAR(2) NOT NULL,
branch CHAR(4),
revenue_total NUMBER(10,2),
cost_total NUMBER(10,2),
fee_total NUMBER(10,2)
);

# inline_constraint

该语句用于定义表的行内约束项。关于约束项的详细描述请参考通用SQL语法constraint

其中,不能为临时表建立FOREIGN KEY约束,也不能为其他表建立到临时表的FOREIGN KEY约束。

# out_of_line_constraint

该语句用于定义表的行外约束项。关于约束项的详细描述请参考通用SQL语法constraint

其中,不能为临时表建立FOREIGN KEY约束,也不能为其他表建立到临时表的FOREIGN KEY约束。

# table_properties

该语句用于指定创建的表的各项属性,多项间以空格进行分隔。

# organization_clause

该语句指定表的数据存储方式(表类型),可省略,则系统按DEFAULT_TABLE_TYPE参数的值创建相应类型的表。YashanDB针对不同表类型的数据存储方式参考产品描述存储架构

HEAP

创建HEAP行存表。

TAC

创建TAC列存表。

LSC

创建LSC列存表,此种表类型要求默认或指定表空间为databucket表空间,否则创建失败。

示例

CREATE TABLE area_tac
(area_no CHAR(2) NOT NULL,
area_name VARCHAR2(60),
DHQ VARCHAR2(20) DEFAULT 'ShenZhen' NOT NULL)
ORGANIZATION TAC;

# temp_table_attr_clause

该语句只针对全局临时表和私有临时表,且DELETE|PRESERVE ROWS只可用于全局临时表,而DROP|PRESERVE DEFINITION只可用于私有临时表。

# on commit delete|preserve rows

指定事务提交后在当前会话中插入的全局临时表的数据是否保留,DELETE为删除,PRESERVE为保留。

示例

--创建全局临时表T_orders_info,并指定PRESERVE ROWS
CREATE GLOBAL TEMPORARY TABLE T_orders_info (
order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10))
ON COMMIT PRESERVE ROWS;
  
--插入数据并提交
INSERT INTO T_orders_info VALUES ('20010102020001','product 001','02','0202',SYSDATE-400,'0001');
COMMIT;
  
--查询结果,由于指定了PRESERVE ROWS,则仍可以查询到数据(且只为本会话插入的数据),如为DELETE ROWS则无法查询到数据
SELECT * FROM T_orders_info;
ORDER_NO          ORDER_DESC     AREA  BRANCH ORDER_DATE             SALESPERSON 
----------------- -------------- ----- ------ ---------------------- -------------
20010102020001    product 001    02    0202   2020-12-06 22:55:32    0001
# on commit drop|preserve definition

指定事务提交后在当前会话中创建的私有临时表是否被删除,DROP为删除,PRESERVE为保留。

示例

--创建私有临时表PTT_orders_info,并指定DROP DEFINITION
CREATE PRIVATE TEMPORARY TABLE YAS$PTT_orders_info (
order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10))
ON COMMIT DROP DEFINITION;
  
--插入数据并提交
INSERT INTO YAS$PTT_orders_info VALUES ('20010102020001','product 001','02','0202',SYSDATE-400,'0001');
COMMIT;
  
--查询结果,由于指定了DROP DEFINITION,事务提交后PTT_orders_info表被删除
SELECT * FROM YAS$PTT_orders_info;
[1:14]YAS-02010 table or view SALES.YAS$PTT_ORDERS_INFO not found

# physical_attribute_clause

该语句用于指定创建的表的物理存储属性。

# tablespace tablespace_name

该语句用于指定表所在的表空间。

对于临时表,只能指定一个temporary类型的表空间,省略则默认为表所属用户所在的表空间(临时表的表空间默认为数据库创建时生成的temporary表空间)。

对于LOB型的列字段,行外存储的LOB数据表空间默认为与表所在表空间一致,也可以单独指定。

对于LSC表,为其所指定的表空间必须拥有bucket属性,详见CREATE TABLESPACE描述。其中,系统的缺省表空间(DEFAULT表空间)已默认拥有bucket属性,可以作为LSC表的表空间。

分布式部署中,创建分布表时不能使用本语句指定表空间。

# tablespace set tablespace_set_name

指定分布表所在的表空间集。省略则默认为内置的USERS表空间集。

# pctfree/pctused/initrans/maxtrans

指定表的PCTFREE/PCTUSED/INITRANS/MAXTRANS属性,省略则默认为8/NULL/2/255。

其中:

  • PCTFREE:表示数据块为数据库对象进行UPDATE保留的空间百分比,当可用空间低于该百分比时无法进行INSERT,只能进行UPDATE。
  • PCTUSED:表示数据块为数据库对象保留的最小已用空间百分比,当数据所占空间低于该百分比时可进行INSERT。
  • INITRANS:表示每个数据块中初始并发事务项的数量。
  • MAXTRANS:表示每个数据块中并发事务项数量的最大值。
# storage_clause

指定为表分配的初始空间和最大空间大小,由于YashanDB采取延迟分配的策略(有数据才分配空间),不建议指定此参数。

示例

CREATE TABLE employee_info (
name CHAR(10) NOT NULL,
age INT,
id INT NOT NULL
)TABLESPACE users PCTFREE 50 PCTUSED 20 INITRANS 3 MAXTRANS 254;

# table_partition_clause

该语句用于为表创建分区(Partition),可通过DBA_TAB_PARTITIONS视图查看所有分区信息。

该语句包含如下限制:

  • 不允许为临时表创建分区。
  • 不允许将LOB列/JSON列指定为分区键。

# range_partitions

创建范围分区,分区列为多项时以,分隔。

如果指定了INTERVAL,那么分区列的数量必须为1,并且只能是数值或者时间类型。

# interval(expr)

创建INTERVAL类型的范围分区。分布式部署中不可创建INTERVAL类型的范围分区。

范围分区根据分区界值将每个分区定义了下限值(即为前一分区的上限值)和上限值(分区界值),最后的一个分区其上限值即为最大的分区界值。指定INTERVAL表示,当要插入的数据超过最大分区界值时,系统将根据如下规则创建一个新分区,并将这行数据插入到新分区中:

  • 新分区由系统自动命名。
  • 新分区的上限值=最大分区界值+INTERVAL值,之后新分区的上限值将成为最大分区界值。
  • 如果最大分区界值已被定义为MAXVALUE,则无法创建新分区,该数据无法插入表。
  • expr为表达式,表达式的结果类型需与分区列字段的数据类型一致。

此时,如表上已建立了分区索引(Local Partitioned Index),则系统在创建新分区的同时,也会创建相应的索引分区。

STORE IN

为INTERVAL分区指定表空间,指定多个表空间以,分隔,则系统在创建新分区时,按照此处定义的顺序,循环使用作为新分区的表空间。未指定本语句时分区的表空间默认为表所在的表空间。分布式部署中用户无法为分区指定表空间,使用表所在的表空间作为所有分区的表空间。

示例

--创建范围分区表orders_info,并指定INTERVAL值
DROP TABLE IF EXISTS orders_info;
CREATE TABLE orders_info (order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
TABLESPACE yashan
PARTITION BY RANGE (id)
INTERVAL (1000)
(PARTITION p_orders_info_1 VALUES LESS THAN (800));
  
--插入三条数据均成功,如未指定INTERVAL值,则只有第一条数据可以插入成功
INSERT INTO orders_info VALUES ('20010102020001','product 001','02','0201',SYSDATE-400,'0001',300);
INSERT INTO orders_info VALUES ('20010102020001','product 001','02','0201',SYSDATE-400,'0001',2000);
INSERT INTO orders_info VALUES ('20010102020001','product 001','02','0201',SYSDATE-400,'0001',20000);
COMMIT;
  
--查询该表上的分区,除p_orders_info_1 分区外,系统自动创建了另外两个分区
SELECT TABLE_NAME t_name,TABLESPACE_NAME ts_name,PARTITION_NAME par_name,HIGH_VALUE par_max FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='ORDERS_INFO';
T_NAME             TS_NAME   PAR_NAME         PAR_MAX  
----------------- ---------- ---------------- ---------
ORDERS_INFO       YASHAN     SYS_P22          20800    
ORDERS_INFO       YASHAN     SYS_P21          2800     
ORDERS_INFO       YASHAN     P_ORDERS_INFO_1  800    

--创建分区键为时间类型的INTERVAL范围分区表
DROP TABLE IF EXISTS orders_info;
CREATE TABLE orders_info (order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
PARTITION BY RANGE (order_date)
INTERVAL (INTERVAL '3' month)
(PARTITION p_firstquarter VALUES LESS THAN (DATE '2000-01-01'));

# range_values_clause

定义范围分区的上限值。

literal

分区列为多项时,则此处的上限值用,分隔并与分区列一一对应。

MAXVALUE

MAXVALUE表示无上限,即超过前一分区的上限的所有数据均进入此分区中,包括NULL。如所有分区列都定义了以MAXVALUE作为上限值的分区,不支持再继续定义MAXVALUE分区。

在定义了MAXVALUE的分区后,不能通过ADD PARTITION语句增加新的分区,仅能通过SPLIT PARTITION语句将已存在分区划分成新的分区。

示例

DROP TABLE IF EXISTS orders_maxvalue;
CREATE TABLE orders_maxvalue(
order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
PARTITION BY RANGE(id)
(PARTITION p_orders_max_1 VALUES LESS THAN (800),
 PARTITION p_orders_max_2 VALUES LESS THAN (1000),
 PARTITION p_orders_max_3 VALUES LESS THAN (1500),
 PARTITION p_orders_max_4 VALUES LESS THAN (MAXVALUE)
);

--创建分区列为多项的范围分区表
DROP TABLE IF EXISTS orders_multikey;
CREATE TABLE orders_multikey(
order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
PARTITION BY RANGE(id,order_date)
(PARTITION p_orders_max_1 VALUES LESS THAN (800,'2010-01-01'),
 PARTITION p_orders_max_2 VALUES LESS THAN (1000,'2010-05-01'),
 PARTITION p_orders_max_3 VALUES LESS THAN (1500,'2010-10-01'),
 PARTITION p_orders_max_4 VALUES LESS THAN (MAXVALUE,'2010-10-01')
);

--所有分区列均定义MAXVALUE分区后继续定义MAXVALUE分区,此时返回错误
DROP TABLE IF EXISTS orders_multimax;
CREATE TABLE orders_multimax(
order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
PARTITION BY RANGE(id,order_date)
(PARTITION p_orders_max_1 VALUES LESS THAN (800,'2010-01-01'),
 PARTITION p_orders_max_2 VALUES LESS THAN (1000,'2010-05-01'),
 PARTITION p_orders_max_3 VALUES LESS THAN (1500,'2010-10-01'),
 PARTITION p_orders_max_4 VALUES LESS THAN (MAXVALUE,'2010-10-01'),
 PARTITION p_orders_max_5 VALUES LESS THAN (MAXVALUE,MAXVALUE),
 PARTITION p_orders_max_6 VALUES LESS THAN (MAXVALUE,MAXVALUE)
);

YAS-04240 partition bound is too high

# table_partition_description

定义范围分区的存储属性。分布式部署中不可定义范围分区的存储属性。

TABLESPACE tablespace_name

为分区指定一个表空间,省略则默认为表所在的表空间。

PCTFREE/PCTUSED/INITRANS/MAXTRANS

指定PCTFREE/PCTUSED/INITRANS/MAXTRANS属性,省略则默认为8/NULL/2/255。

各属性定义同physical_attribute_clause语句中描述一致。

示例

--单机部署中创建定义了存储属性的范围分区
DROP TABLE IF EXISTS sales_info_range;
CREATE TABLE sales_info_range
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4),
 product CHAR(5),
 quantity NUMBER DEFAULT 0 NOT NULL,
 amount NUMBER(10,2) DEFAULT 0 NOT NULL,
 salsperson CHAR(10))
PARTITION BY RANGE(year)
(PARTITION p_sales_info_range_1 VALUES LESS THAN('2011') PCTFREE 3,
 PARTITION p_sales_info_range_2 VALUES LESS THAN('2021'),
 PARTITION p_sales_info_range_3 VALUES LESS THAN('2031'));

# list_partitions

创建列表分区,分区列为多项时以,分隔。

# list_values_clause

定义列表分区的列表内容。

DEFAULT

DEFAULT表示将在已定义列表值之外的所有数据均进入此分区中,如不指定DEFAULT分区,插入已定义列表值之外的所有数据会报错。如指定,须作为最后一个分区指定,且DEFAULT分区不支持指定多次。

在定义了DEFAULT的分区后,不能通过ADD PARTITION语句增加新的分区,仅能通过SPLIT PARTITION语句将已存在分区划分成新的分区。

list_values

分区列为多项时,须用,分隔并与分区列一一对应,该列表内容须指定为字面量或NULL。

# table_partition_description

范围分区描述一致。

示例

--创建列表分区的销售信息表
DROP TABLE IF EXISTS sales_info;
CREATE TABLE sales_info
(year CHAR(4) NOT NULL,
month CHAR(2) NOT NULL,
branch CHAR(4) NOT NULL,
product CHAR(10) NOT NULL,
quantity NUMBER DEFAULT 0 NOT NULL,
amount NUMBER(10,2) DEFAULT 0 NOT NULL,
salsperson CHAR(10))
PARTITION BY LIST(year,month)
(PARTITION p_sales_info1_1 VALUES (('2018','01'),('2018','02')),
PARTITION p_sales_info1_2 VALUES ('2020','01'),
PARTITION p_sales_info1_3 VALUES (DEFAULT)
);

# hash_partitions

创建哈希分区,分区列为多项时以,分隔,哈希分区有如下两种创建方式:

  • 逐个指定哈希分区。
  • 使用hash分数批量指定哈希分区。

# individual_partition_clause

本语句用于逐个指定哈希分区,对每个分区分别定义其名称和存储属性,分区之间用,分隔。

partition_storage_clause

定义哈希分区的存储属性。

TABLESPACE tablespace_name

为分区指定一个表空间,省略则默认为表所在的表空间。

分布式部署中用户无法为分区指定表空间,使用表所在的表空间作为所有分区的表空间。

示例

--单机部署中
DROP TABLE IF EXISTS sales_info_hash;
CREATE TABLE sales_info_hash
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4),
 product CHAR(5),
 quantity NUMBER DEFAULT 0 NOT NULL,
 amount NUMBER(10,2) DEFAULT 0 NOT NULL,
 salsperson CHAR(10))
PARTITION BY HASH(year)
(PARTITION p_sales_info_hash_1,
 PARTITION p_sales_info_hash_2);
 
--单机部署中为分区指定表空间,分布式部署中不支持此操作
DROP TABLE IF EXISTS sales_info_hashpar;
CREATE TABLE sales_info_hashpar
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4))
PARTITION BY HASH(year) 
(PARTITION p_sales_info_hash_1 TABLESPACE users,
 PARTITION p_sales_info_hash_2);

# hash_partitions_by_quantity

本语句用于按hash分数批量指定哈希分区,所有分区名称由系统生成。

hash_partition_quantity

表示hash分数的数量。

STORE IN

STORE IN子句描述hash分区所属的表空间,表空间可指定多个,且数量不需要与分区的数量一致, 系统将按本语句中表空间指定的顺序进行循环归属。

不指定本语句时,系统默认使用表所在的表空间作为所有分区的表空间。

分布式部署中用户无法为分区指定表空间,使用表所在的表空间作为所有分区的表空间。

示例

--单机部署中通过hash分数创建哈希分区表,并指定STORE IN语句
DROP TABLE IF EXISTS sales_info_hash;
CREATE TABLE sales_info_hash
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4),
 product CHAR(5),
 quantity NUMBER DEFAULT 0 NOT NULL,
 amount NUMBER(10,2) DEFAULT 0 NOT NULL,
 salsperson CHAR(10))
PARTITION BY HASH(year)
PARTITIONS 4
STORE IN (ts1,ts2);

--分布式部署中不支持指定STORE IN语句
DROP TABLE IF EXISTS sales_info_hash;
CREATE TABLE sales_info_hash
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4),
 product CHAR(5),
 quantity NUMBER DEFAULT 0 NOT NULL,
 amount NUMBER(10,2) DEFAULT 0 NOT NULL,
 salsperson CHAR(10))
PARTITION BY HASH(year)
PARTITIONS 4;

# shard_distribute_clause

该语句用于指定分布表的分布键分配规则,YashanDB支持的规则为:

  • 按指定的列或列组合进行哈希分配
  • 需符合类型要求
  • 如果表上定义了主键列,则分布键必须为主键列的其中一项或多项
  • 如果表上未定义主键列,则分布键可以为任意项

此语句可省略,则默认的哈希分配列为:

  • 如果表上定义了主键列,则分布键列为主键列
  • 如果表上未定义主键列,但存在唯一索引, 则分布键为所有唯一索引的公共子集中首个恰当数据类型的字段
  • 否则, 分布键为表的首个恰当数据类型的列字段

分布键定义后无法进行修改。

示例(在建立了两个节点的分布式数据库中)

--重新创建销售信息表,且要求按年和月的组合哈希分配数据到各节点中
DROP TABLE IF EXISTS sales_info;
CREATE TABLE sales_info
(year CHAR(4) NOT NULL,
 month CHAR(2) NOT NULL,
 branch CHAR(4),
 product CHAR(5),
 quantity NUMBER DEFAULT 0 NOT NULL,
 amount NUMBER(10,2) DEFAULT 0 NOT NULL,
 salsperson CHAR(10))
DISTRIBUTE BY HASH (year,month);
 
INSERT INTO sales_info VALUES ('2001','01','0201','11001',30,500,'0201010011');
INSERT INTO sales_info VALUES ('2015','11','0101','11001',20,300,'');
INSERT INTO sales_info VALUES ('2021','10','0101','11001',20,300,'');
INSERT INTO sales_info VALUES ('2000','12','0102','11001',20,300,'');
INSERT INTO sales_info VALUES ('2015','03','0102','11001',20,300,'');
INSERT INTO sales_info VALUES ('2021','05','0101','11001',40,600,'');
COMMIT;
 
--节点1
SELECT * FROM sales_info;
YEAR  MONTH BRANCH PRODUCT      QUANTITY      AMOUNT SALSPERSON   
----- ----- ------ --------- ----------- ----------- -------------
2015  11    0101   11001              20         300             
2021  10    0101   11001              20         300             
2000  12    0102   11001              20         300             
 
--节点2
SELECT * FROM sales_info;
YEAR  MONTH BRANCH PRODUCT      QUANTITY      AMOUNT SALSPERSON   
----- ----- ------ --------- ----------- ----------- -------------
2001  01    0201   11001              30         500 0201010011  
2015  03    0102   11001              20         300             
2021  05    0101   11001              40         600

# lob_clause

该语句用于指定LOB/JSON类型列字段的存储属性,同时指定多列用,分隔。

# basicfile|securefile

该语句用于语法兼容,无实际含义。

# tablespace

指定LOB/JSON数据进行行外存储时的表空间,不指定该属性时LOB/JSON数据存储在表所在表空间中。

# disable storage in row

指定对于LOB/JSON列字段,无论其大小,都执行行外存储,即为其创建新的存储空间,而不是与行中的其他列字段数据存储在一起。

# enable storage in row

指定将LOB/JSON列字段的数据存放在行内空间,即与行中的其他列字段数据存储在一起。但当该数据大小超过4000字节时,即使指定了ENABLE STORAGE IN ROW,仍会按照DISABLE STORAGE IN ROW方式进行行外存储。

Note

数据在存储时会产生一些内部元信息,上述4000字节也包括这部分元数据所占空间。

示例

--创建一张员工信息表,其中introduce为超长文本的LOB类型字段
CREATE TABLE employees1(area CHAR(2),
branch CHAR(4),
employee_info JSON,
introduce CLOB)
LOB(introduce,employee_info) STORE AS (TABLESPACE yashan ENABLE STORAGE IN ROW);
  
--插入两行数据,其中第一行数据里的introduce因为数据长度小于3988字节,采用的是行内存储,而第二行数据则采用的是行外存储,json字段长度小于3988字节,采用的是行内存储。
INSERT INTO employees1 VALUES ('04','0401',
JSON('{"employee_no":"0401010008","employee_name":"Sam1","sex":"1","entire_date":"SYSDATE-3"}'),
'深圳计算科学研究院是深圳市人民政府2018年11月批准建设的十大基础研究机构之一');
INSERT INTO employees1 VALUES ('04','0401',
JSON('{"employee_no":"0401010008","employee_name":"Sam2","sex":"1","entire_date":"SYSDATE-3"}'),
LPAD('深圳',4000,'深圳'));
COMMIT;
 
SELECT JSON_FORMAT(employee_info), LENGTHB(introduce) FROM employees1;
JSON_FORMAT(EMPLOYEE                                                LENGTHB(INTRODUCE) 
---------------------------------------------------------------- --------------------- 
{"sex":"1","employee_no":"0401010008","entire_date":"SYSDATE-3","employee_name":"Sam1"}                   108
{"sex":"1","employee_no":"0401010008","entire_date":"SYSDATE-3","employee_name":"Sam2"}                 12000

# logging_clause

用于指定表的logging属性,默认为logging。logging描述请参考CREATE TABLE的logging_clause部分。

# parallel_clause

用于指定后续查询创建的表对象时,默认的并行度。

# deferred_segment_creation

用于指定创建表对象时,segment是否立即创建,语法兼容,无实际含义。

# cache_clause

语法兼容,无实际含义。

# readonly_clause

语法兼容,无实际含义。

# inmemory_clause

语法兼容,无实际含义。

# table_compression

语法兼容,无实际含义。

# nested_table_clause

该语句用于定义和创建嵌套表,YashanDB中的嵌套表被用于实现与含有Nested Table类型的UDT(用户自定义类型)列的存储,详见数据类型中关于用户自定义类型的描述。

# nested_item

指定嵌套表对应的列字段,或列字段属性(该属性为Nested Table类型)。

# column_value

当出现多层嵌套表(列字段为一个行成员包含Nested Table类型的Nested Table集合)时,对于里层的嵌套表使用COLUMN_VALUE关键字来表示nested_item。

# local|global

当主表为分区表时,使用LOCAL关键字指定嵌套表也为与主表一一对应的分区,使用GLOBAL关键字指定嵌套表不分区,省略关键字时默认为LOCAL。

# storage_table

指定嵌套表的名称,不可省略,且需符合YashanDB的对象命名规范

对于多层嵌套表,在名称后接(nested_table_clause)定义里层的嵌套表信息。

# tablespace

为嵌套表指定独立的表空间,省略时默认嵌套表存储在与主表相同的表空间。

示例

DROP TABLE IF EXISTS area_intro;
DROP TABLE IF EXISTS province_intro;
CREATE OR REPLACE TYPE tb_type AS TABLE OF CHAR(10);
/
CREATE OR REPLACE TYPE obj_type AS OBJECT(city_id INT, branch_list tb_type);
/

--创建单层嵌套表
CREATE TABLE province_intro (id INT, citys tb_type, city_intro obj_type)
NESTED TABLE citys STORE AS nt_province_citys TABLESPACE yashan
NESTED TABLE city_intro.branch_list STORE AS nt_province_branch;

--创建多层嵌套表
CREATE OR REPLACE TYPE tb_type_city AS TABLE OF tb_type;
/
CREATE TABLE area_intro(id INT, provinces tb_type_city)
NESTED TABLE provinces STORE AS nt_area_provinces(
    NESTED TABLE COLUMN_VALUE STORE AS nt_nt_province_citys);

# lsc_table_properties

该语句用于定义LSC表的专有属性,这些属性只可以在创建LSC表时指定,否则报错。

# compression_clause

定义LSC表的压缩属性,同列字段定义的压缩属性描述,系统按此设置对所有列数据进行压缩存储。

# table_sort_clause

本语句用于定义LSC表的排序键,其中排序列可以是表中的任意列(可组合),不指定本语句时,默认以第一列作为排序键,且默认值为NULL FIRST ASC。

YashanDB在存储LSC表数据时,会自适应的按照一定的排序粒度对存储进行排序。通过本语句所指定的排序键仅作为加速属性使用,即当对表执行查询、更新或删除等操作时,如过滤条件中包含已定义的排序键,系统将在存储层进行排序加速计算,从而获得更优的查询性能。

# column_name

本语句用于指定表的排序列,排序列不支持为如下类型:

  • CLOB
  • BLOB
  • NCLOB
  • BIT
  • ROWID
  • CURSOR
  • JSON
  • UDT
# nulls (first|last)

本语句用于指定空值的排列位置,NULLS FIRST表示空值排列在最前,NULLS LAST表示空值排列在最后。当未指定此语句时,对升序排列缺省为NULLS LAST,对降序排列缺省为NULLS FIRST。

# asc|desc

本语句用于指定排序方式,ASC表示升序,DESC表示降序,省略则默认为升序。

示例

--创建LSC表,压缩且按指定列排序存储
DROP TABLE IF EXISTS finance_info;
CREATE TABLE finance_info
(year CHAR(4) NOT NULL,
month CHAR(2) NOT NULL,
branch CHAR(4),
revenue_total NUMBER(10,2),
cost_total NUMBER(10,2),
fee_total NUMBER(10,2)
)
COMPRESSION lz4 HIGH
ORDER BY (year,month,branch);

# mcol_ttl_clause

该语句用于定义LSC表的可变数据生命周期。

在YashanDB中,对LSC表插入的数据将先作为可变数据(MCOL)存储,满足一定条件后触发后台线程将可变数据转为稳态数据(SCOL,不可变数据)进入数据桶(bucket,对象存储目录)。

指定了可变数据生命周期后,系统将把该值和数据量一起作为触发转换线程的条件,让用户可以根据自身业务情况设定更合理的转换时间。

timestamp

生命周期数值,该值须遵循INTERVAL YEAR TO MONTH或INTERVAL DAY TO SECOND数据类型的格式表述,例如'1' YEAR(9)'30:59.9' MINUTE TO SECOND(6),具体请参考日期型中这两种类型的描述。

示例

--创建可变数据生命周期为1个月的LSC表,即在满1个月且数据行数达到阈值时,MCOL数据将被转换为SCOL数据
DROP TABLE IF EXISTS finance_info;
CREATE TABLE finance_info
(year CHAR(4) NOT NULL,
month CHAR(2) NOT NULL,
branch CHAR(4),
revenue_total NUMBER(10,2),
cost_total NUMBER(10,2),
fee_total NUMBER(10,2)
)
COMPRESSION lz4 HIGH
ORDER BY (year,month,branch)
MCOL TTL '1' MONTH;

# row_movement_clause

该语句用于指定创建的表中的行数据是否可以物理移动,省略则默认为DISABLE ROW MOVEMENT。分布式暂不支持开启row movement。

在YashanDB中,默认行的Rowid是不变化的,但在某些特殊场景,例如对分区表的分区键值进行更新操作,导致其所在行需要从当前分区迁移到另一个分区中,行的Rowid将发生变更,这种变动在表ENABLE ROW MOVEMENT时是被允许的,且YashanDB在此情况下会保证事务的强一致性,避免出现漏更新(lost update)。

开启row movement后,并发事务中可能会触发语句重启(restart statement,回滚之前的操作并重新执行DML事务),影响并发性能 ,因此在正常情况下不建议开启此开关,在可预知会发生行迁移的业务场景中(例如闪回数据),可通过ALTER TABLE语句临时打开,并在结束后关闭。

示例

--创建一张ENABLE ROW MOVEMENT的分区表
DROP TABLE IF EXISTS orders_info_rowmove;
CREATE TABLE orders_info_rowmove (order_no CHAR(14) NOT NULL,
order_desc VARCHAR2(100),
area CHAR(2),
branch CHAR(4),
order_date DATE DEFAULT SYSDATE NOT NULL,
salesperson CHAR(10),
id NUMBER)
PARTITION BY RANGE (id )
(PARTITION p1 VALUES LESS THAN (800),
PARTITION p2 VALUES LESS THAN (1800),
PARTITION p3 VALUES LESS THAN (2800))
ENABLE ROW MOVEMENT;