交换分区
你可以通过交换数据段将一个分区(或子分区)转化为一个非分区表,也可以将一个非分区表转化为一个分区表的分区(或子分区)。你也可以将一个哈希分区表转化为一个复合哈希分区表的一个分区,或者将一个复合哈希分区表的一个分区转化为一个哈希分区表。类似的,你可以将一个【范围|列表】分区表转化为一个复合【范围|列表】分区表的一个分区,或者将一个复合【范围|列表】分区表的一个分区转化为一个【范围|列表】分区表。
当你有一个需要将非分区表转化成一个分区表的分区的应用时,交换表分区是非常有用的。例如,在数据仓库环境下,交换分区有利于将新增数据快速加载到一个现存分区表。一般来说,OLTP和数据仓库都受益于从一个分区表中交换出旧的分区数据。该数据从分区表中清除,而无需实际删除,并可以在以后分别归档。
当你交换分区时,日志属性将被保留。你可以指定本地索引是否也进行交换(INCLUDING INDEXES子句),并且可以指定行是否以合适的映射进行验证(WITH VALIDATION子句)。
注意:
当你给交换分区操作指定WITHOUT VALIDATION子句时,这通常是一个非常快速的操作,因为它只涉及到更新数据字典。但是,如果交换操作涉及到的表或者分区表启用了主键或者唯一约束,那么执行交换操作时会默认执行WITH VALIDATION选项来维持约束的完整性。
为了避免这种情况下验证操作的开销,在执行交换分区操作之前为每个约束执行以下语句:
- ALTER TABLE table_name
- DISABLE CONSTRAINT constraint_name KEEP INDEX;
然后,在交换分区操作完成后,重新启用约束。
如果你指定了WITHOUT VALIDATION,那么你必须确保要交换的数据属于你执行交换操作的分区。
除非你指定了UPDATE INDEXES,否则数据库会将执行交换分区所属表的全局索引或者所有全局索引分区标识为UNUSABLE。执行交换分区所属表的全局索引或者所有全局索引分区仍然无效(你不能在索引组织表上使用UPDATE INDEXES,可以使用UPDATE GLOBAL INDEXES来代替)。
交换一个范围、哈希或列表分区
如果要拿一个非分区表和范围分区、哈希分区或者列表分区表的一个分区进行交换,可以使用ALTER TABLE ... EXCHANGE PARTITION语句;反之亦然。下面是将一个分区转化为一个非分区表的例子。在这个例子中,表stocks可以是范围分区、哈希分区或者列表分区表。
- ALTER TABLE stocks
- EXCHANGE PARTITION p3 WITH TABLE stock_table_3;
交换间隔分区表的一个分区
你可以在一个间隔分区表中交换间隔分区。但是,你必须确保在交换分区之前该间隔分区已经创建。你可以让数据库通过锁定间隔分区来创建分区。
下面的例子显示了interval_sales分区表的一个分区交换,该间隔分区表以月为间隔,就像2004年1月1日。这个例子显示了如何通过交换分区向该间隔分区表加载添加2007年6月份的数据。我们假设interval_sales表只有本地索引,并且表interval_sales_june_2007上等价的索引已经被创建。
- LOCK TABLE interval_sales
- PARTITION FOR (TO_DATE('01-JUN-2007','dd-MON-yyyy'))
- IN SHARE MODE;
- ALTER TABLE interval_sales
- EXCHANGE PARTITION FOR (TO_DATE('01-JUN-2007','dd-MON-yyyy'))
- WITH TABLE interval_sales_jun_2007
- INCLUDING INDEXES;
注意FOR语法的使用,是用来标识系统生成的一个分区。该分区名称可用于通过查询*_TAB_PARTITIONS数据字典视图来查找系统生成分区的名称。
交换引用分区表的一个分区
你可以在一个引用分区表中交换分区,但是你必须确保在父表的相应分区中你引用的数据是可用的。
例4-30显示了范围分区表orders和引用分区表order_items的一个分区交换加载场景。注意order_items_dec_2006表的数据只包含order_date在2006月12月份的订单的详细数据。
- 例4-30 给交换分区表交换一个分区
- ALTER TABLE orders
- EXCHANGE PARTITION p_2006_dec
- WITH TABLE orders_dec_2006
- UPDATE GLOBAL INDEXES;
- ALTER TABLE order_items_dec_2006
- ADD CONSTRAINT order_items_dec_2006_fk
- FOREIGN KEY (order_id)
- REFERENCES orders(order_id) ;
- ALTER TABLE order_items
- EXCHANGE PARTITION p_2006_dec
- WITH TABLE order_items_dec_2006;
需要注意的是,你必须在父表的交换分区上使用UPDATE GLOBAL INDEXES或者UPDATE INDEXES,这样可以确保主键索引保持可用。另外,也要注意你必须在order_items_dec_2006表上创建或者启用外键约束,以便在引用分区表上的分区交换可以执行成功。
交换表的一个分区和虚拟列
你可以在包含虚拟列的情况下进行交换分区。为了使包含虚拟列的分区表的分区交换成功,你必须创建一个表,该表需要匹配分表中一个分区的所有非虚拟列的定义。你并不需要包括虚拟列定义,除非虚拟列上定义的有约束或者索引。
在这种情况下,你必须包含虚拟列定义,用来匹配分区表的约束和索引定义。该方案也适用于基于虚拟列的分区表。
交换一个哈希分区表和一个复合哈希分区
在这个例子中,你交换的是一个哈希分区表(包含所有分区)和一个复合哈希分区表的分区(包含所有子分区)。下面的例子说明了一个范围哈希分区表的定义。
首先,创建一个哈希分区表:
- CREATE TABLE t1 (i NUMBER, j NUMBER)
- PARTITION BY HASH(i)
- (PARTITION p1, PARTITION p2);
填充该表后,创建一个范围哈希分区表,如下:
- CREATE TABLE t2 (i NUMBER, j NUMBER)
- PARTITION BY RANGE(j)
- SUBPARTITION BY HASH(i)
- (PARTITION p1 VALUES LESS THAN (10)
- SUBPARTITION t2_pls1
- SUBPARTITION t2_pls2,
- PARTITION p2 VALUES LESS THAN (20)
- SUBPARTITION t2_p2s1
- SUBPARTITION t2_p2s2));
其中,t1表的分区键等于t2表的子分区键,这一点很重要。
要将t1表的数据迁移到t2表,并且验证行数据,使用以下语句:
- ALTER TABLE t2 EXCHANGE PARTITION p1 WITH TABLE t1
- WITH VALIDATION;
交换复合哈希分区表的一个子分区
使用ALTER TABLE ... EXCHANGE SUBPARTITION语句将一个复合哈希分区表的一个哈希分区转化为一个非分区表,反之亦然。下面的例子将sales表的子分区q3_1999_s1转化为非分区表q3_1999。本地索引分区与分区q3_1999上相关的索引进行交换。
- ALTER TABLE sales EXCHANGE SUBPARTITION q3_1999_s1
- WITH TABLE q3_1999 INCLUDING INDEXES;
交换一个列表分区表和一个复合列表分区
ALTER TABLE ... EXCHANGE PARTITION语句的含义和上面“交换一个哈希分区表和一个复合哈希分区”章节的描述是一样的。下面的例子显示了一个列表-列表分区表的分区交换方案。
- CREATE TABLE customers_apac
- ( id NUMBER
- , name VARCHAR2(50)
- , email VARCHAR2(100)
- , region VARCHAR2(4)
- , credit_rating VARCHAR2(1)
- )
- PARTITION BY LIST (credit_rating)
- ( PARTITION poor VALUES ('P')
- , PARTITION mediocre VALUES ('C')
- , PARTITION good VALUES ('G')
- , PARTITION excellent VALUES ('E')
- );
用亚太地区客户填充该表,然后创建一个列表-列表分区表:
- CREATE TABLE customers
- ( id NUMBER
- , name VARCHAR2(50)
- , email VARCHAR2(100)
- , region VARCHAR2(4)
- , credit_rating VARCHAR2(1)
- )
- PARTITION BY LIST (region)
- SUBPARTITION BY LIST (credit_rating)
- SUBPARTITION TEMPLATE
- ( SUBPARTITION poor VALUES ('P')
- , SUBPARTITION mediocre VALUES ('C')
- , SUBPARTITION good VALUES ('G')
- , SUBPARTITION excellent VALUES ('E')
- )
- (PARTITION americas VALUES ('AMER')
- , PARTITION emea VALUES ('EMEA')
- , PARTITION apac VALUES ('APAC')
- );
其中,customers_apac表的分区键等于customers表的子分区键,这一点很重要。
接下来,交换apac分区:
- ALTER TABLE customers
- EXCHANGE PARTITION apac
- WITH TABLE customers_apac
- WITH VALIDATION;
交换复合列表分区表的一个子分区
ALTER TABLE ... EXCHANGE SUBPARTITION语句的含义和上面“交换复合哈希分区表的一个子分区”章节的描述是一样的。
交换一个范围分区表和一个复合范围分区
ALTER TABLE ... EXCHANGE PARTITION语句的含义和上面“交换一个哈希分区表和一个复合哈希分区”章节的描述是一样的。下面的例子涉及到表orders,该表以order_date作为间隔分区键,并以列order_total作为范围子分区键值。该例子显示如何将一个单月间隔分区和一个范围分区���进行交换。
- CREATE TABLE orders_mar_2007
- ( id NUMBER
- , cust_id NUMBER
- , order_date DATE
- , order_total NUMBER
- )
- PARTITION BY RANGE (order_total)
- ( PARTITION p_small VALUES LESS THAN (1000)
- , PARTITION p_medium VALUES LESS THAN (10000)
- , PARTITION p_large VALUES LESS THAN (100000)
- , PARTITION p_extraordinary VALUES LESS THAN (MAXVALUE)
- );
用2007年3月份的订单数据填充该表,然后创建一个间隔-范围复合分区表:
- CREATE TABLE orders
- ( id NUMBER
- , cust_id NUMBER
- , order_date DATE
- , order_total NUMBER
- )
- PARTITION BY RANGE (order_date) INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
- SUBPARTITION BY RANGE (order_total)
- SUBPARTITION TEMPLATE
- ( SUBPARTITION p_small VALUES LESS THAN (1000)
- , SUBPARTITION p_medium VALUES LESS THAN (10000)
- , SUBPARTITION p_large VALUES LESS THAN (100000)
- , SUBPARTITION p_extraordinary VALUES LESS THAN (MAXVALUE)
- )
- (PARTITION p_before_2007 VALUES LESS THAN (TO_DATE('01-JAN-2007','dd-
- MON-yyyy')));
其中,orders_mar_2007表的分区键等于orders表的子分区键,这一点很重要。
接下来,交换分区。需要注意的是,由于要交换一个间隔分区,因此首先要锁定该分区以确保该分区被创建。
- LOCK TABLE orders PARTITION FOR (TO_DATE('01-MAR-2007','dd-MON-yyyy'))
- IN SHARE MODE;
- ALTER TABLE orders
- EXCHANGE PARTITION
- FOR (TO_DATE('01-MAR-2007','dd-MON-yyyy'))
- WITH TABLE orders_mar_2007
- WITH VALIDATION;
交换复合范围分区表的一个子分区
ALTER TABLE ... EXCHANGE SUBPARTITION语句的含义和上面“交换复合哈希分区表的一个子分区”章节的描述是一样的。