您的位置:首页 > 数据库 > Oracle

Oracle 11g新特性-分区

2014-03-15 10:39 375 查看
在以前的版本中分区只有range,list,hash这么三种,而组合分区也仅仅有range-list和range-hash两种搭配方式,但在oracle 11g中分区功能得到了极大的加强,可以说是相当的给力:)

除上述提到的分区外新增了:
1. 间隔分区(Interval-Partitioned)

DBA在日常工作中有一项工作就是对那些需要进行扩展的分区表增加新分区;或者是对以前的MAX分区重新进行整理,可见这项工作有多么的无趣,但值得庆幸的是在oracle 11g中这部分工作可以由系统自动完成,即采用间隔分区特性来实现.

顾名思义,你只需要定义了一个分区边界的间隔即可,当新增数据超过现有分区的分界时,系统会自动为新增数据建立新的分区.

在创建间隔分区时必须要确保至少要有一个range分区,并且间隔的类型只能是number或者date.

下面通过具体示例来说明:

(1). 间隔类型是number:

首先让我们创建一个数值间隔分区

CREATE TABLE interval_sales_num

( prod_id        NUMBER(6),

amount_sold    NUMBER(10,2))

PARTITION BY RANGE (amount_sold)

INTERVAL(100)

STORE IN (ts1,ts2,ts3)

(PARTITION p0 VALUES LESS THAN (100));

通过查看user_tab_partitions我们可以发现目前此表上只有一个分区,并且这个分区的high_value是100,然后我  们再新插入一条新记录,此记录要超过当前分区的最大值;

SQL> insert into interval_sales_num(amount_sold) values (300);

可以想象如果是在以前的版本中,由于我们没有定义MAX分区,在插入过程中就会报错,但在11g中执行完命令后,系统会自动建立一个新分区,而新生成的分区high_value则是400.同时可以发现,不管这个transaction是否已经被commit,新的分区总是会生成,个人认为Oracle应该存在一个类似于before statement的触发器来创建新分区.

假如再插入一个大于p0分区并且小于新分区的值时,系统会为这个新值重新创建属于它的分区;

SQL> insert into interval_sales_num(amount_sold) values (250);

此时再查看user_tab_partitions表会发现一共有3个分区;

SQL>select * from user_tab_partitions where table_name=’INTERVAL_SALES_NUM’;

(2). 间隔类型是date:

除了number类型外,还可以使用date进行间隔分界,一般来说这种情况比较常见.此类型的基本过程大致与上述相同,只不过是使用NUMTOYMINTERVAL函数来对日期进行分区罢了.

首先还是让我们先来创建一个日期间隔分区,然后再新插入一条超过当前最大值的记录

CREATE TABLE interval_sales_date

( prod_id        NUMBER(6),

time_id          DATE)

PARTITION BY RANGE (time_id)

INTERVAL(NUMTOYMINTERVAL(1, ‘YEAR’))

( PARTITION p0 VALUES LESS THAN (TO_DATE(’1-1-2009′, ‘DD-MM-YYYY’)));

SQL> insert into interval_sales_date (time_id) values (sysdate);

在此示例中系统会自动创建一个最大值为2012-01-01的新分区.同样,你也可以使用store in参数来指定新分区依次将使用哪个表空间来存储数据;你还可以将’YEAR’更改为’MONTH’,即以月份来进行间隔而不以年.

需要注意的是间隔分区不能作为组合分区的子分区出现.
2. 引用分区(Reference-Partitioned)

在日常设计数据模型时,我们有时会创建父-子表结构.例如在一个订单系统中通常会有orders与order_items两张表用来记录订单与订单明细信息,同时为了在业务逻辑上保持一致则会将order_items设置为字表,毕竟明细信息是依赖于订单信息的.

此时可能会对orders表按照时间进行分区,以便月底进行对账及相关业务活动.相应的,在理想状况下,我们也希望order_items按照相同的列进行分区,但很不凑巧的是在表上根本就没有这样的列!那么如何处理这种情况呢?

在11g中提供引用分区的功能,下面的示例展示了如何在order_items表上应用此特性:

CREATE TABLE orders

( order_id           NUMBER(12) PRIMARY KEY,

order_date         DATE,

order_mode         VARCHAR2(8),

customer_id        NUMBER(6))

PARTITION BY RANGE(order_date)

( PARTITION Q1_2011 VALUES LESS THAN (TO_DATE(’01-01-2011′,’DD-MM-YYYY’)),

PARTITION Q2_2011 VALUES LESS THAN (TO_DATE(’01-02-2011′,’DD-MM-YYYY’)),

PARTITION Q3_2011 VALUES LESS THAN (TO_DATE(’01-03-2011′,’DD-MM-YYYY’))

);

CREATE TABLE order_items

( order_id           NUMBER(12) NOT NULL,

line_item_id       NUMBER(3)  NOT NULL,

product_id         NUMBER(6)  NOT NULL,

unit_price         NUMBER(8,2),

quantity           NUMBER(8),

CONSTRAINT order_items_fk

FOREIGN KEY(order_id) REFERENCES orders(order_id)

)

PARTITION BY REFERENCE(order_items_fk);

SQL> select * from user_tab_partitions where table_name in (‘ORDER_ITEMS’,'ORDERS’);

从user_tab_partitions的查询结果来看,order_items表虽然没有名为order_date的列,但仍根据父表orders对该表创建了相同的分区.

在使用引用分区特性时,有一些需要注意的地方:

a. 子表中需要使用引用分区的字段不能为NULL;

b. 父表中被子表外键关联的字段一定要是unique或者是primary key
3. 虚拟分区(Virtual Column-Based Partitioning)

在某些应用中有时候需要对计算后的结果进行分区.例如在销售系统的sales表中存在两个字段:quantity和price,我们想要根据销售金额进行分区;在以前的版本中只能新增一个字段表示合计,进而对这个字段进行分区;但在11g中由于引进了虚拟字段的概念,因此可以直接对虚拟字段进行分区.

下面的示例就展示了如何使用虚拟分区来实现:

CREATE TABLE sales

( prod_id       NUMBER(6) NOT NULL,

time_id       DATE NOT NULL,

quantity NUMBER(3) NOT NULL,

price   NUMBER(10,2) NOT NULL,

total_amount AS (quantity * price)

)

PARTITION BY RANGE (time_id) INTERVAL (NUMTOYMINTERVAL(1,’MONTH’))

SUBPARTITION BY RANGE(total_amount)

SUBPARTITION TEMPLATE

( SUBPARTITION p_small VALUES LESS THAN (10),

SUBPARTITION p_medium VALUES LESS THAN (50),

SUBPARTITION p_large VALUES LESS THAN (100),

SUBPARTITION p_extreme VALUES LESS THAN (MAXVALUE)

)

(PARTITION sales_before_2011 VALUES LESS THAN (TO_DATE(’01-01-2011′,’DD-MM-YYYY’)))

ENABLE ROW MOVEMENT

PARALLEL NOLOGGING;
4. 系统分区(System Partitioning)

对于某些应用无法使用任何逻辑方法来进行分区时,系统分区会是个不错的选择,虽然这种情况发生的不多.

通过指定partition的个数,系统会自动创建相应个数的分区;如果不指定分区个数,默认值则为1;也可以为每个分区定义名称;

具体示例如下:

a. 指定分区个数:

create table system_partition

(

prod_id       NUMBER(6) NOT NULL,

time_id       DATE NOT NULL

)

partition by system PARTITIONS 6;

SQL> select * from user_tab_partitions where table_name in (‘SYSTEM_PARTITION’);

可以看到系统一次为system_partition表创建了6个分区;

b. 不指定分区个数:

create table system_partition

(

prod_id       NUMBER(6) NOT NULL,

time_id       DATE NOT NULL

)

partition by system;

SQL> select * from user_tab_partitions where table_name in (‘SYSTEM_PARTITION’);

可以看到系统只创建了1个分区;

c. 定义每个分区名称:

create table system_partition

(

prod_id       NUMBER(6) NOT NULL,

time_id       DATE NOT NULL

)

partition by system

(

partition p1 tablespace users,

partition p2 tablespace users

);

SQL> select * from user_tab_partitions where table_name in (‘SYSTEM_PARTITION’);

可以看到分区的名称不再是SYS_Pn,而是你指定的名称;

至此你可能会有疑问?当我插入数据的时候,oracle是怎么知道应该放在哪个分区中的.其实oracle是并不知道的,所以在维护数据的时候,程序员是必须要指定分区的.

我们先创建一个自定义名称的分区,然后再下列操作:

a. 插入操作:如果没有指定分区名称,在执行过程中则会报ORA-14701错误,要求你指定分区;

SQL>insert into system_partition partition(p1) values (1,sysdate);

b. 删除操作:虽然不像插入操作需要指定分区,但由于系统分区是没有边界的概念,因此在删除某条记录时Oracle会扫描所有分区以得到该记录;为了避免这种情况,提高效率,一般还是推荐限定分区;

SQL>delete system_partition partition(p1) where prod_id=1;

c. 更新操作:与删除操作一样,推荐限定分区;

SQL>update system_partition partition(p1) set prod_id=1 where prod_id=2;

oracle除了增强分区外,还对组合分区进行了扩展,在该版本中,并不局限于范围-散列和范围-列表组合分区,可以使用任何以list及range为父分区的组合分区. 具体的示例在此就不进行列举,你可以参考oracle的官方文档:http://download.oracle.com/docs/cd/E11882_01/server.112/e16541/part_admin001.htm#i1006565

单个分区的表空间传输
在 Oracle 数据库的早期版本中,你能够传输表空间,并且稍后能将其插入不同数据库或同一个数据库中.该过程涉及复制数据文件,因此它是跨数据库传输数据的最快方法.然而直到现在,你仍然无法传输单个分区的表空间,然后再将其插回数据库中.在 Oracle 数据库 11g 中,你可以这么做.

假设您有一个名为 SALES的表,为这个表创建P1,P2两个系统分区,我们要对分区P1进行表空间传输试验:

create table sales

(

sales_id   number,

product_code number,

state_code   number

)

partition by system

(

partition p1 tablespace t1,

partition p2 tablespace t2

);

然后你可以执行如下脚本,将P1这个分区导出;在执行命令之前,要确保表相关的tablespace是处于read only状态.

SQL> alter tablespace t1 read only;

C:\> expdp hr/hr tables=hr.sales:p1 transportable=always directory=data_pump_dir dumpfile=p_p1.dmp

Export: Release 11.2.0.1.0 – Production on Tue Mar 29 14:44:14 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 – Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

Starting “HR”.”SYS_EXPORT_TABLE_01″:  hr/******** tables=hr.sales:p1 transportable=always directory=data_pump_dir dumpfile=p_p1.dmp

Processing object type TABLE_EXPORT/TABLE/PLUGTS_BLK

Processing object type TABLE_EXPORT/TABLE/TABLE

Processing object type TABLE_EXPORT/TABLE/END_PLUGTS_BLK

Master table “HR”.”SYS_EXPORT_TABLE_01″ successfully loaded/unloaded

******************************************************************************

Dump file set for HR.SYS_EXPORT_TABLE_01 is:

D:\ORACLE\ADMIN\DIABLO\DPDUMP\P_P1.DMP

******************************************************************************

Datafiles required for transportable tablespace T1:

D:\ORACLE\ORADATA\DIABLO\T1.DBF

Job “HR”.”SYS_EXPORT_TABLE_01″ successfully completed at 14:44:31

现在,可以将生成的P_P1.DMP 和T1.DBF这两个文件传递到其他系统,然后再插入到数据库中.

在此为了方便,我仅在相同数据库中进行试验.

首先需要删除该表,然后删除 t1 表空间:

SQL> drop table sales

SQL> drop tablespace t1 including contents;

这里有个小问题:sales表不存在,而最初只导出了一个分区 (P1),并不是整个表.那么如何只导入不存在的表的一个分区呢?在 Oracle 数据库 11g 中,Data Pump导入中的一个名为partition_options的新命令行选项可实现此操作.如果指定了值departition,Data Pump将根据导出的分区创建一个新表.该方法以这种方式“拆分”分区,因此它相应地被命名为取消分区.我们来看一下它的工作原理,执行如下命令:

C:\> impdp hr/hr partition_options=departition dumpfile=p_p1.dmp transport_datafiles=’D:\oracle\oradata\diablo\T1.DBF’;

Import: Release 11.2.0.1.0 – Production on Tue Mar 29 14:52:44 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 – Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

Master table “HR”.”SYS_IMPORT_TRANSPORTABLE_01″ successfully loaded/unloaded

Starting “HR”.”SYS_IMPORT_TRANSPORTABLE_01″:  hr/******** partition_options=departition dumpfile=p_p1.dmp transport_data

files=’D:\oracle\oradata\diablo\T1.DBF’

Processing object type TABLE_EXPORT/TABLE/PLUGTS_BLK

Processing object type TABLE_EXPORT/TABLE/TABLE

Processing object type TABLE_EXPORT/TABLE/END_PLUGTS_BLK

Job “HR”.”SYS_IMPORT_TRANSPORTABLE_01″ successfully completed at 14:52:48

通过查看dba_tables或者dba_segments表可以发现oracle新创建了一个名为SALES_P1的表,该表只是由先前导出的sales表的p1分区,表名是原始表名和分区名的组合.

SQL> select * from dba_tables where tablespace_name=’T1′;

SQL> select * from dba_segments where tablespace_name=’T1′;

你还可以在表生成后,使用分区交换(exchange)特性,再将此表置于某表上作为分区.

author: lynch0227

forward from: http://lynch0227.wordpress.com/2011/03/29/oracle-11g%E6%96%B0%E7%89%B9%E6%80%A7-%E5%88%86%E5%8C%BA/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: