CREATE TABLE...PARTITION BY

使用CREATE TABLE命令的PARTITION BY子句来创建一个分区表,这个分区表中的数据分配在一个或多个分区(和子分区)中。

语法介绍

CREATE TABLE命令语法有下面的三种形式:

  • 列表分区语法

    使用第一种形式创建一个列表分区表:

    CREATE TABLE [ schema. ]table_name
     table_definition
       PARTITION BY LIST(column)
       [SUBPARTITION BY {RANGE|LIST|HASH} (column[, column ]...)]
       (list_partition_definition[, list_partition_definition]...);

    其中list_partition_definition是:

    PARTITION [partition_name]
      VALUES (value[, value]...)
      [TABLESPACE tablespace_name]
      [(subpartition, ...)]
  • 范围分区语法

    使用第二种形式创建范围分区表:

    CREATE TABLE [ schema. ]table_name
     table_definition
       PARTITION BY RANGE(column[, column ]...)
       [SUBPARTITION BY {RANGE|LIST|HASH} (column[, column ]...)]
       (range_partition_definition[, range_partition_definition]...);

    其中range partition definition是:

    PARTITION [partition_name]
      VALUES LESS THAN (value[, value]...)
      [TABLESPACE tablespace_name]
      [(subpartition, ...)]
  • 子分区语法

    subpartition可能是下面两种的其中一种

    {list_subpartition | range_subpartition }

    其中list_subpartition是:

    SUBPARTITION [subpartition_name]
      VALUES (value[, value]...)
      [TABLESPACE tablespace_name]

    其中range_subpartition是:

    SUBPARTITION [subpartition_name]
      VALUES LESS THAN (value[, value]...)
      [TABLESPACE tablespace_name]

描述

CREATE TABLE... PARTITION BY命令用于创建带有一个或多个分区的表,其中每个分区可能有一个或一个以上的子分区。对于定义的分区数量没有上限, 但如果您要包括PARTITION BY子句,则必须至少指定一个分区规则。产生的表由创建这个表的用户所有。

使用PARTITION BY LIST子句在指定列中输入的值的基础上对表进行分区。每个分区规则必须至少指定一个文本值,但对于您可能要指定的值的数量则没有上限。包括一个用于指定DEFAULT匹配值的规则将任何不符合的记录导入到指定的分区中。

使用PARTITION BY RANGE子句指定边界规则来创建分区。每个分区规则必须至少包含一列有两个运算符的数据类型(例如,一个大于等于运算符和一个小于运算符)。范围边界的评估是依据LESS THAN子句进行的,且范围边界是非包容性的。2013年1月1日这个日期边界只会包括那些在2012年12月31日当天及之前的日期值。

范围分区规则必须以升序方式指定。 如果INSERT命令存储的记录值超过了范围分区表的最大限制将会失败。除非分区规则中包括的边界规则指定了MAXVALUE值。如果您没有包括MAXVALUE分区规则,那么任何超过边界规则指定的最大限制的记录都会导致错误的产生。

使用关键字TABLESPACE指定分区或子分区要所属的表空间名称。如果您没有指定表空间, 那么分区或子分区则会所属于缺省表空间。

如果您使用CREATE TABLE语法在分区表上创建索引,那么这个索引也会同样创建于每个分区或子分区中。

如果表定义包括SUBPARTITION BY子句, 那么这个表中的每个分区都会有至少一个子分区。每个子分区可能是明确定义的或是系统定义的。

如果子分区是系统定义的,那么服务器产生的子分区将所属于缺省表空间中,且子分区的名称将由服务器指定。服务器会创建下列内容:

  • 如果SUBPARTITION BY子句指定了LIST, 那么服务器会创建一个DEFAULT子分区。

  • 如果SUBPARTITION BY子句指定了RANGE,那么服务器会创建一个MAXVALUE子分区。

服务器所产生的子分区名称是分区表名称与一个唯一标识符的结合。您可以查询表ALL_TAB_SUBPARTITIONS来检查完整的子分区名称列表。

参数

参数

参数说明

table name

要创建的表名称(可以采用模式限定的方式引用)。

table definition

如在PostgreSQL核心文件中描述的那样,给create table语句的列名称、数据类型及约束信息。

partition name

要创建的分区名称。分区名称在所有分区和子分区中必须是唯一的,且必须遵循给对象标识符命名的惯例。

subpartition name

要创建的子分区名称。子分区名称在所有分区和子分区中必须是唯一的,且必须遵循给对象标识符命名的惯例。

column

分区规则所基于的列名称。 每条记录都将存储在一个符合于指定列值的分区中。

(value[, value]...)

value来指定一个引用的文本值(或以逗号分隔的文本值列表)将表项目划分为不同的分区。每个分区规则必须至少指定一个值,但在规则中对于指定的值的数量没有上限要求。Value可能为null default(如果指定了一个list分区的话) 或 maxvalue(如果指定了一个range 分区的话)。

当给列表分区表指定规则时,要在最后的分区中包括关键字default来把任何不匹配的记录导入到指定分区中。如果您没有使用一个包括default值的规则,那么任何insert语句试图添加一条与(至少一个分区的)指定规则不匹配的记录都会失败,并返回错误。

当给范围分区表指定规则时,在最后的分区规则中包括关键字maxvalue来把所有未分类的记录导入到指定分区中。如果不包括maxvalue分区,那么在分区键大于指定最高值的情况下,insert语句试图添加记录的操作将会失败,并返回错误。

tablespace name

分区或子分区所属的表空间名称。

PARTITION BY LIST示例

下列示例使用了PARTITION BY LIST子句创建了分区表(sales)。表sales在三个分区(europe、 asia 和 americas)中存储信息:

CREATE TABLE sales
(
  dept_no     number,   
  part_no     varchar2,
  country     varchar2(20),
  date        date,
  amount      number
)
PARTITION BY LIST(country)
(
  PARTITION europe VALUES('FRANCE', 'ITALY'),
  PARTITION asia VALUES('INDIA', 'PAKISTAN'),
  PARTITION americas VALUES('US', 'CANADA')
);

在country列中指定的值对所产生的表进行了分区:

SELECT partition_name, high_value from ALL_TAB_PARTITIONS;
 partition_name |     high_value      
----------------+---------------------
 americas       | 'US', 'CANADA'      
 asia           | 'INDIA', 'PAKISTAN' 
 europe         | 'FRANCE', 'ITALY'   
(3 rows)
  • Country列中带有US或CANADA值的记录存储于americas分区中。

  • Country列中带有INDIA 或 PAKISTAN值的记录存储于asia分区中。

  • Country列中带有FRANCE 或 ITALY值的记录存储于europe分区中。

服务器会依据分区规则对下列语句进行评估,并将记录存储在europe分区中:

INSERT INTO sales VALUES (10, '9519a', 'FRANCE', '18-Aug-2012', '650000');

PARTITION BY RANGE示例

下列示例使用了PARTITION BY RANGE子句创建了分区表(sales)。表sales在四个分区(q1_2012、 q2_2012、 q3_2012 和 q4_2012)中存储信息。

CREATE TABLE sales
(
  dept_no     number,
  part_no     varchar2,
  country     varchar2(20),
  date        date,
  amount      number
)
PARTITION BY RANGE(date)
(
  PARTITION q1_2012 
    VALUES LESS THAN('2012-Apr-01'),
  PARTITION q2_2012 
    VALUES LESS THAN('2012-Jul-01'),
  PARTITION q3_2012 
    VALUES LESS THAN('2012-Oct-01'),
  PARTITION q4_2012 
    VALUES LESS THAN('2013-Jan-01')
);

在date列中指定的值对产生的表进行了分区。

SELECT partition_name, high_value from ALL_TAB_PARTITIONS;
 partition_name |                            high_value                            
----------------+------------------------------------------------------------------
 q1_2012        | FOR VALUES FROM (MINVALUE) TO ('01-APR-12 00:00:00')
 q2_2012        | FOR VALUES FROM ('01-APR-12 00:00:00') TO ('01-JUL-12 00:00:00')
 q3_2012        | FOR VALUES FROM ('01-JUL-12 00:00:00') TO ('01-OCT-12 00:00:00')
 q4_2012        | FOR VALUES FROM ('01-OCT-12 00:00:00') TO ('01-JAN-13 00:00:00')
(4 rows)
  • 在date列中任何带有2012年4月1日之前的值的记录都存储于q1_2012分区中。

  • 在date列中任何带有2012年7月1日之前的值的记录都存储于分区q2_2012中。

  • 在date列中任何带有2012年10月1日之前的值的记录都存储于分区q3_2012中。

  • 在date列中任何带有2013年1月1日之前的值的记录都存储于分区q4_2012中。

服务器会依据分区规则对下列语句进行评估,并将记录存储在q3_2012分区中。

INSERT INTO sales VALUES (10, '9519a', 'FRANCE', '18-Aug-2012', '650000');

PARTITION BY RANGE、SUBPARTITION BY LIST示例

下列示例创建的分区表(sales)首先是通过事务日期进行分区。然后使用country列的值对范围分区(q1_2012、 q2_2012、 q3_2012 和 q4_2012)进行了列表子分区的划分。

CREATE TABLE sales
(
  dept_no     number,
  part_no     varchar2,
  country     varchar2(20),
  date        date,
  amount      number
)
PARTITION BY RANGE(date)
  SUBPARTITION BY LIST(country)
  (
    PARTITION q1_2012 
      VALUES LESS THAN('2012-Apr-01')
      (
        SUBPARTITION q1_europe VALUES ('FRANCE', 'ITALY'),
        SUBPARTITION q1_asia VALUES ('INDIA', 'PAKISTAN'),
        SUBPARTITION q1_americas VALUES ('US', 'CANADA')
       ),
  PARTITION q2_2012 
    VALUES LESS THAN('2012-Jul-01')
      (
        SUBPARTITION q2_europe VALUES ('FRANCE', 'ITALY'),
        SUBPARTITION q2_asia VALUES ('INDIA', 'PAKISTAN'),
        SUBPARTITION q2_americas VALUES ('US', 'CANADA')
       ),
  PARTITION q3_2012 
    VALUES LESS THAN('2012-Oct-01')
      (
        SUBPARTITION q3_europe VALUES ('FRANCE', 'ITALY'),
        SUBPARTITION q3_asia VALUES ('INDIA', 'PAKISTAN'),
        SUBPARTITION q3_americas VALUES ('US', 'CANADA')
       ),
  PARTITION q4_2012 
    VALUES LESS THAN('2013-Jan-01')
      (
        SUBPARTITION q4_europe VALUES ('FRANCE', 'ITALY'),
        SUBPARTITION q4_asia VALUES ('INDIA', 'PAKISTAN'),
        SUBPARTITION q4_americas VALUES ('US', 'CANADA')
       )
);

这条语句创建的表有四个分区。每个分区都有三个子分区:

SELECT subpartition_name, high_value, partition_name FROM ALL_TAB_SUBPARTITIONS;
 subpartition_name |             high_value              | partition_name 
-------------------+-------------------------------------+----------------
 q1_americas       | FOR VALUES IN ('US', 'CANADA')      | q1_2012
 q1_asia           | FOR VALUES IN ('INDIA', 'PAKISTAN') | q1_2012
 q1_europe         | FOR VALUES IN ('FRANCE', 'ITALY')   | q1_2012
 q2_americas       | FOR VALUES IN ('US', 'CANADA')      | q2_2012
 q2_asia           | FOR VALUES IN ('INDIA', 'PAKISTAN') | q2_2012
 q2_europe         | FOR VALUES IN ('FRANCE', 'ITALY')   | q2_2012
 q3_americas       | FOR VALUES IN ('US', 'CANADA')      | q3_2012
 q3_asia           | FOR VALUES IN ('INDIA', 'PAKISTAN') | q3_2012
 q3_europe         | FOR VALUES IN ('FRANCE', 'ITALY')   | q3_2012
 q4_americas       | FOR VALUES IN ('US', 'CANADA')      | q4_2012
 q4_asia           | FOR VALUES IN ('INDIA', 'PAKISTAN') | q4_2012
 q4_europe         | FOR VALUES IN ('FRANCE', 'ITALY')   | q4_2012
(12 rows)

当把记录添加到这个表中时,就会把date列中的值与在范围分区规则中指定的值进行比较,服务器会选择记录应该所属的分区。然后country列中的值就会与在列表子分区规则中指定的值相比较。当服务器定位了值的匹配信息时,记录就会存储在相应的子分区中。

任何添加到表中的记录都会存储在子分区中,因此所有的分区中都不会包含任何数据。

服务器会依据分区和子分区规则对下列语句进行评估,并将记录存储在q3_europe分区中:

INSERT INTO sales VALUES (10, '9519a', 'FRANCE', '18-Aug-2012', '650000');