Oracle分区表例子
分区表
Oracle提供的分区方法有以下几种。
1.范围分区(range)
范围分区是应用范围比较广的表分区方式,它是以列的值的范围来作为分区的划分条
件,将记录存放到列值所在的 range分区中。
示例 1
需求说明:
在某购物中心销售系统中,要求统计某季度的销售信息。
销售信息表包含如下列:销售流水号、产品 id、销售日期、销售金额、销售区域。
表 1 销售信息表 SALES
列名称 列类型 列说明
SALES_ID NUMBER 销售流水号
PRODUCT_ID VARCHAR2(5) 产品 id
SALES_DATE DATE 销售日期
SALES_COST NUMBER(10) 销售金额
AREACODE VARCHAR2(5) 销售区域
解决方案一:没学过表分区时,根据要求查询的季度找到对应的所有月份,找出相应的
记录,求和汇总来分析。
解决方案二:运用表分区的特性,根据范围分区的概念,按照季度将销售记录表创建为
范围分区表,某一季度的数据就包含在某一个分区中,只查询某一分区的数据就可获得该季
度的销售信息,而不用进行全表的筛选,从而提高数据库性能。
分析:
如按照时间划分,2013年 4月 1日前的数据放到 P1分区,代表第一季度;2013年 7月
1日前的数据放到 P2分区,代表第二季度;2013年 10月 1日前的数据放到 P3分区,代表
第三季度;2014年 1月 1日前的数据放到 P4分区,代表第四季度。在创建的时候,需要指
定基于的列,以及分区的范围值。
提示:
在按时间分区时,如果某些记录暂无法预测范围,可以创建 maxvalue分区,所有不在
指定范围内的记录都会被存储到 maxvalue所在分区中。
关键代码:
CREATE TABLE SALES1
(
1
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY RANGE (SALES_DATE)
(
PARTITION P1 VALUES LESS THAN (to_date('2013-04-1', 'yyyy-mm-dd')),
PARTITION P2 VALUES LESS THAN (to_date('2013-07-1', 'yyyy-mm-dd')),
PARTITION P3 VALUES LESS THAN (to_date('2013-10-1', 'yyyy-mm-dd')),
PARTITION P4 VALUES LESS THAN (to_date('2014-01-1', 'yyyy-mm-dd')),
PARTITION P5 VALUES LESS THAN (maxvalue)
);
要查看在第三季度的数据,请输入以下语句。
SELECT SUM(sales_cost) FROM SALES1 partition(P3);
经验
一般创建范围分区时都会将最后一个分区设置为 maxValue,将其他数据落入
此分区,一旦需要时可以利用拆分分区的技术将需要的数据从最后一个分区分离
出去,单独形成一个分区。如果没有创建最大的分区,插入的数据超出范围就会
报错。
如果插入的数据就是分区键上的值,则该数据落入下一分区。例如插入数据位
‘2013-10-1',则数据会落入 P4 分区。
2.散列分区(hash)
对于那些无法有效划分范围的表,可以使用 hash分区。hash分区会将表中的数据平均
分配到指定的几个分区中,由于数据被平均分配到不同的分区,减少了查询时对数据块的竞
争,这样对于提高性能还是会有一定的帮助。列所在分区是依据分区列的 hash值自动分配,
因此并不能控制,也不知道哪条记录会被放到哪个分区中,hash分区也可以支持多个依赖
列。
示例 2
需求说明:
根据散列分区的特性,为了提高数据库的性能,将销售流水号作为分区键创建销售记录
表。
关键代码:
--准备工作,提前创建每个分区的表空间
--创建散列分区表
CREATE TABLE SALES2
2
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY HASH (SALES_ID)
(
PARTITION P1 tablespace tablespace01,
PARTITION P2 tablespace tablespace02,
PARTITION P3 tablespace tablespace03
);
3.列表分区(list)
列表分区也需要指定列的值,其分区值必须明确指定,该分区列只能有一个,不能像
range或者 hash分区那样同时指定多个列作为分区依赖列,但它的单个分区对应值可以是
多个。
在分区时,必须确定分区列可能存在的值,一旦插入的列值不在分区范围内,则插入/
更新就会失败,因此通常建议使用 list分区时,要创建一个 default分区存储那些不在指
定范围内的记录,类似 range分区中的 maxvalue分区。
示例 3
需求说明:
按照销售区域统计销售记录。
分析:
创建列表分区,分区键为销售区域代码列。
提示:
可以指定 default,把非分区规则的数据全部放到 default分区。
关键代码:
CREATE TABLE SALES3
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY LIST(AREACODE)
(
PARTITION t_list025035 VALUES ('025','035'),
PARTITION t_list372 VALUES ('372') ,
PARTITION t_list510 VALUES ('510'),
PARTITION t_other VALUES (default)
3
);
4.复合分区
如果某表按照某列分区之后,仍然较大,或者有一些其他的需求,还可以通过分区内再
建子分区的方式将分区再分区,即组合分区的方式。
组合分区有两种:
范围-哈希(range-hash)复合分区。
范围-列表(range-list)复合分区。
注意顺序,根分区只能是 range分区,子分区可以是 hash分区或 list分区。
示例 4
需求说明:
查找某一季度的销售信息。
分析:
先根据销售日期进行范围分区,再在每个分区内根据销售流水号进行散列分区。
优点:
可以按照范围查找,在每个范围内进行散列分区,提高数据库性能。
关键代码:
CREATE TABLE SALES4
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY RANGE (SALES_DATE)
SUBPARTITION BY HASH(SALES_ID)
SUBPARTITIONS 3 STORE in (tablespace01,tablespace02,tablespace03)
(
PARTITION P1 VALUES LESS THAN (to_date('2013-04-1', 'yyyy-mm-dd')),
PARTITION P2 VALUES LESS THAN (to_date('2013-07-1', 'yyyy-mm-dd')),
PARTITION P3 VALUES LESS THAN (to_date('2013-10-1', 'yyyy-mm-dd')),
PARTITION P4 VALUES LESS THAN (to_date('2014-01-1', 'yyyy-mm-dd')),
PARTITION p5 VALUES LESS THAN (maxvalue)
);
示例 5
需求说明:
4
要求查找某一季度内的某一销售区域的销售信息。
分析:
先根据交易日期进行范围分区,再在每个分区内根据销售区域进行列表分区。
优点:
可以按照范围查找,在每个范围内还可以用列表分区进行细分。
关键代码:
CREATE TABLE SALES5
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY RANGE (SALES_DATE)
SUBPARTITION BY LIST(AREACODE)
(
PARTITION P1 VALUES LESS THAN (to_date('2013-04-1', 'yyyy-mm-dd'))
(SUBPARTITION t1_list025035 VALUES ('025','035'),
SUBPARTITION t1_list372 VALUES ('372') ,
SUBPARTITION t1_list510 VALUES ('510'),
SUBPARTITION t1_other VALUES (default)
),
PARTITION P2 VALUES LESS THAN (to_date('2013-07-1', 'yyyy-mm-dd'))
(SUBPARTITION t2_list025035 VALUES ('025','035'),
SUBPARTITION t2_list372 VALUES ('372') ,
SUBPARTITION t2_list510 VALUES ('510'),
SUBPARTITION t2_other VALUES (default)
),
PARTITION P3 VALUES LESS THAN (to_date('2013-10-1', 'yyyy-mm-dd'))
(SUBPARTITION t3_list025035 VALUES ('025','035'),
SUBPARTITION t3_list372 VALUES ('372') ,
SUBPARTITION t3_list510 VALUES ('510'),
SUBPARTITION t3_other VALUES (default)
),
PARTITION P4 VALUES LESS THAN (to_date('2014-01-1', 'yyyy-mm-dd'))
(SUBPARTITION t4_list025035 VALUES ('025','035'),
SUBPARTITION t4_list372 VALUES ('372') ,
SUBPARTITION t4_list510 VALUES ('510'),
SUBPARTITION t4_other VALUES (default)
),
PARTITION p5 VALUES LESS THAN (maxvalue)
(SUBPARTITION t5_list025035 VALUES ('025','035'),
SUBPARTITION t5_list372 VALUES ('372'),
SUBPARTITION t5_list510 VALUES ('510'),
SUBPARTITION t5_other VALUES (default)
5
)
);
要查看在第三季度并且在销售区域编号为“510”地区的数据,请输入以下语句。
--查复合分区子分区的关键字为 subpartition
SELECT SUM(SALES_COST) FROM SALES5 subpartition(t3_list510);
5.间隔分区(Interval)
Interval分区是 Oracle11g版本新引入的分区方法,使范围分区的一种增强功能,可以
实现范围分区的自动化。
优点为不需要创建表时将所有分区划分清楚,间隔分区随着数据的增加会分配更多的分
区,并自动创建新的分区。
示例 6
需求说明:
参照示例 1,要求统计某季度的销售信息。
关键代码:
--创建间隔分区表
CREATE TABLE SALES5
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5)
)
PARTITION BY RANGE(SALES_DATE)
INTERVAL(NUMTOYMINTERVAL(3,'MONTH'))
(PARTITION P1 VALUES LESS THAN (to_date('2013-04-1','yyyy/mm/dd')));
--插入数据
INSERT INTO sales5 VALUES (1,'a',to_date('2013-08-1'),10,'1');
--获得分区情况
SELECT table_name,partition_name
FROM user_tab_partitions
WHERE table_name=UPPER('sales5');
--查询输出结果,系统自动根据输入数据情况创建新分区“SYS_P82”
TABLE_NAME PARTITION_NAME
----------------------------
SALES5 P1
SALES5 SYS_P82
--查询分区数据
SELECT * FROM sales5 PARTITION(sys_P82);
说明:
6
(1)只需创建第一个开始分区,如上例中 P1。
(2)INTERVAL(NUMTOYMINTERVAL(3,'MONTH'))语句含义。其中 INTERVAL代表“间隔”,
按照后面括号中的定义间隔添加分区;
(3)NUMTOYMINTERVAL(3,'MONTH')函数的意思为每 3个月为一个分区。
NUMTOYMINTERVAL(n, 'interval_unit') 函数
将 n转换成 interval_unit所指定的值,
interval_unit可以为: YEAR, MONTH
举例:NUMTOYMINTERVAL(1,'YEAR'):每 1年为一个分区;
NUMTOYMINTERVAL(1,'MONTH'):每 1个月为一个分区;
与该类型相关的函数还有:
NUMTODSINTERVAL(n, 'interval_unit')
将 n转换成 interval_unit所指定的值,
interval_unit可以为: DAY, HOUR, MINUTE, SECOND
注意该函数不可以转换成 YEAR和 MONTH的.
(4)系统会根据数据自动创建分区。
经验
可以利用间隔分区将开始创建时没有分区的表创建为间隔分区表。例如
CREATE TABLE SALES5
PARTITION BY RANGE(SALES_DATE)
INTERVAL(NUMTOYMINTERVAL(3,'MONTH'))
(PARTITION P1 VALUES LESS THAN (to_date('2013-04-1','yyyy/mm/dd')))
AS SELECT * FROM SALES; --SALES表为已经创建的表
6.虚拟列分区
在之前的 Oracle版本中,只有分区键存在于表中才可以对该表实施分区操作。Oracle11g
新功能“虚拟列分区” 打破了这一限制,允许虚拟列作为分区建。
下面是一个创建虚拟列的表的例子。
示例 7
需求说明:
创建销售纪录分区表,根据销售区域编码前 2位创建一个虚拟列为销售部门列。以销售
部门列作为分区建。
分析:
7
获得销售区域编码前 2位代码:
to_number(SUBSTR(to_char(AREACODE),1,2))
创建销售部门列代码:
AREA_Branch NUMBER(2) GENERATED ALWAYS AS
(to_number(SUBSTR(to_char(AREACODE),1,2)))
关键代码:
CREATE TABLE SALES6
(
SALES_ID NUMBER,
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE NOT NULL,
SALES_COST NUMBER(10),
AREACODE VARCHAR2(5),
AREA_Branch NUMBER(2) GENERATED ALWAYS AS
(to_number(SUBSTR(to_char(AREACODE),1,2)))
)
PARTITION BY LIST(AREA_Branch)
(
PARTITION t_list10 VALUES (10),
PARTITION t_list11 VALUES (11) ,
PARTITION t_list12 VALUES (12),
PARTITION t_other VALUES (default)
);
--插入数据
INSERT INTO sales6(SALES_ID,PRODUCT_ID,SALES_DATE, SALES_COST,AREACODE) VALUES
(1,'a',to_date('2013-08-1'),10,'1012');
--查询数据
select * FROM sales6 PARTITION (t_list10);
说明:
(1)虚拟列是不能插入数据的,虚拟列是通过其他列或者其他虚拟列计算出来的。