oracle分区表的使用和查询
一 . 创建和使用分区表
1.范围分区(RANGE)
- 1)每一个分区都必须有一个VALUES LESS THEN子句,它指定了一个不包括在该分区中的上限值。分区键的任何值等于或者大于这个上限值的记录都会被加入到下一个高一些的分区中。
- 2)所有分区,除了第一个,都会有一个隐式的下限值,这个值就是此分区的前一个分区的上限值。
- 3)在最高的分区中,MAXVALUE被定义。MAXVALUE代表了一个不确定的值。这个值高于其它分区中的任何分区键的值,也可以理解为高于任何分区中指定的VALUE LESS THEN的值,同时包括空值。
CREATE TABLE CUSTOMER ( CUSTOMER_ID NUMBER NOT NULL PRIMARY KEY, FIRST_NAME<span style="white-space:pre"> </span>VARCHAR2(30) NOT NULL, LAST_NAME<span style="white-space:pre"> </span>VARCHAR2(30) NOT NULL, PHONE<span style="white-space:pre"> </span>VARCHAR2(15) NOT NULL, EMAIL<span style="white-space:pre"> </span>VARCHAR2(80), STATUS<span style="white-space:pre"> </span>CHAR(1) ) PARTITION BY RANGE (CUSTOMER_ID) ( PARTITION CUS_PART1 VALUES LESS THAN (100000) TABLESPACE CUS_TS01, PARTITION CUS_PART2 VALUES LESS THAN (200000) TABLESPACE CUS_TS02 );
例二:按时间划分
CREATE TABLE ORDER_ACTIVITIES ( ORDER_ID NUMBER(7) NOT NULL, ORDER_DATE DATE, TOTAL_AMOUNT NUMBER, CUSTOTMER_ID NUMBER(7), PAID CHAR(1) ) PARTITION BY RANGE (ORDER_DATE) ( PARTITION ORD_ACT_PART01 VALUES LESS THAN (TO_DATE('01- MAY -2003','DD-MON-YYYY')) TABLESPACEORD_TS01, PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUN-2003','DD-MON-YYYY')) TABLESPACE ORD_TS02, PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUL-2003','DD-MON-YYYY')) TABLESPACE ORD_TS03 );
例三:MAXVALUE
CREATE TABLE RANGETABLE ( idd INT PRIMARY KEY , iNAME VARCHAR(10), grade INT ) PARTITION BY RANGE (grade) ( PARTITION part1 VALUES LESS THEN (1000) TABLESPACE Part1_tb, PARTITION part2 VALUES LESS THEN (MAXVALUE) TABLESPACE Part2_tb ); --——在表上执行查询 select * from RANGETABLE; --——在表分区上执行查询 select * from RANGETABLE partition(part1);
2.列表分区(LIST)
该分区的特点是某列的值只有几个,基于这样的特点我们可以采用列表分区。创建一个按字段数据列表固定可枚举值分区的表。插入记录分区字段的值必须在列表中,否则不能被插入。
例一:
<span style="font-size: 12px;"><span style="font-family:SimSun;">CREATE TABLE PROBLEM_TICKETS ( PROBLEM_ID NUMBER(7) NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR2(2000), CUSTOMER_ID NUMBER(7) NOT NULL, DATE_ENTERED DATE NOT NULL, STATUS VARCHAR2(20) ) PARTITION BY LIST (STATUS) ( PARTITION PROB_ACTIVE VALUES ('ACTIVE') TABLESPACE PROB_TS01, PARTITION PROB_INACTIVE VALUES ('INACTIVE') TABLESPACE PROB_TS02 );</span></span><span style="font-family:georgia, verdana, Arial, helvetica, sans-seriff;font-size:14px;"> </span>
例二:
<span style="font-family:SimSun;font-size:12px;">CREATE TABLE ListTable ( id INT PRIMARY KEY , name VARCHAR (20), area VARCHAR (10) ) PARTITION BY LIST (area) ( PARTITION part1 VALUES ('guangdong','beijing') TABLESPACE Part1_tb, PARTITION part2 VALUES ('shanghai','nanjing') TABLESPACE Part2_tb );</span>
3.哈希分区(散列分区)(HASH)
CREATE TABLE HASH_TABLE ( COL NUMBER(8), INF VARCHAR2(100) ) PARTITION BY HASH (COL) ( PARTITION PART01 TABLESPACE HASH_TS01, PARTITION PART02 TABLESPACE HASH_TS02, PARTITION PART03 TABLESPACE HASH_TS03 )
简写:
CREATE TABLE emp ( empno NUMBER (4), ename VARCHAR2 (30), sal NUMBER ) PARTITION BY HASH (empno) PARTITIONS 8 STORE IN (emp1,emp2,emp3,emp4,emp5,emp6,emp7,emp8);
hash分区最主要的机制是根据hash算法来计算具体某条纪录应该插入到哪个分区中,hash算法中最重要的是hash函数,Oracle中如果你要使用hash分区,只需指定分区的数量即可。建议分区的数量采用2的n次方,这样可以使得各个分区间数据分布更加均匀。
4.组合分区(RANGE-LIST 和 RANGE-HASH)
CREATE TABLE SALES ( PRODUCT_ID VARCHAR2(5), SALES_DATE DATE, SALES_COST NUMBER(10), STATUS VARCHAR2(20) ) PARTITION BY RANGE(SALES_DATE) SUBPARTITION BY LIST (STATUS) ( PARTITION P1 VALUES LESS THAN(TO_DATE('2003-01-01','YYYY-MM-DD'))TABLESPACE rptfact2009 ( SUBPARTITION P1SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009, SUBPARTITION P1SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009 ), PARTITION P2 VALUES LESS THAN (TO_DATE('2003-03-01','YYYY-MM-DD')) TABLESPACE rptfact2009 ( SUBPARTITION P2SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009, SUBPARTITION P2SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009 ) )
2)基于范围分区和散列分区,表首先按某列进行范围分区,然后再按某列进行散列分区。
create table dinya_test ( transaction_id number primary key, item_id number(8) not null, item_description varchar2(300), transaction_date date ) partition by range(transaction_date) subpartition by hash(transaction_id) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03) ( partition part_01 values less than(to_date(‘2006-01-01','yyyy-mm-dd')), partition part_02 values less than(to_date(‘2010-01-01','yyyy-mm-dd')), partition part_03 values less than(maxvalue) );
CREATE TABLE range_hash_example( range_column_key int, hash_column_key INT, DATA <span style="white-space:pre"> </span>VARCHAR2(20) ) PARTITION BY RANGE(range_column_key) SUBPARTITION BY HASH(hash_column_key) SUBPARTITIONS 2 ( PARTITION part_1 VALUES LESS THAN (100000000) ( SUBPARTITION part_1_sub_1, SUBPARTITION part_1_sub_2, SUBPARTITION part_1_sub_3 ), PARTITION part_2 VALUES LESS THAN (200000000) ( SUBPARTITION part_2_sub_1, SUBPARTITION part_2_sub_2 ) );
–注: subpartitions 2 并不是指定subpartition的个数一定为2,实际上每个分区的子分区个数可以不同。如果不指定subpartition的具体明细,则系统按照subpartitions的值指定subpartition的个数生成子分区,名称由系统定义 。
二. 有关分区表的维护操作
1.添加分区
ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD'));
注意:以上添加的分区界限应该高于最后一个分区界限。
以下代码给SALES表的P3分区添加了一个P3SUB1子分区
ALTER TABLE SALES MODIFY PARTITION P3 ADD SUBPARTITION P3SUB1 VALUES('COMPLETE');
-- range partitioned table ALTER TABLE range_example ADD PARTITION part04 VALUES LESS THAN (TO_DATE('2008-10-1 00:00:00','yyyy-mm-ddhh24:mi:ss')); --list partitioned table ALTER TABLE list_example ADD PARTITION part04 VALUES('TE'); --Adding Values for a List Partition ALTER TABLE list_example MODIFY PARTITION part04 ADD VALUES('MIS'); --Dropping Values from a List Partition ALTER TABLE list_example MODIFY PARTITION part04 DROP VALUES('MIS'); --hash partitioned table ALTER TABLE hash_example ADD PARTITION part03; --增加subpartition ALTER TABLE range_hash_example MODIFY PARTITION part_1 ADD SUBPARTITION part_1_sub_4; 注:hash partitioned table新增partition时,现有表的中所有data都有重新计算hash值,然后重新分配到分区中,所以被重新分配的分区的indexes需要rebuild 。
2.删除分区
ALTER TABLE SALES DROP PARTITION P3; ALTER TABLE SALES DROP SUBPARTITION P4SUB1;
3.截断分区
ALTER TABLE SALES TRUNCATE PARTITION P2;
通过以下代码截断子分区:
ALTER TABLE SALES TRUNCATE SUBPARTITION P2SUB2;
4.合并分区
ALTER TABLE SALES MERGE PARTITIONS P1,P2 INTO PARTITION P2 UPDATE INDEXES;
–如果省略update indexes子句的话,必须重建受影响的分区的index;
ALTER TABLE range_example MODIFY PARTITION part02 REBUILD UNUSABLE LOCAL INDEXES;
5.拆分分区
ALTER TABLE SALES SBLIT PARTITION P2 AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION P21,PARTITION P22);
注意:如果是RANGE类型的,使用at,LIST类型的使用values。
6.接合分区(coalesce)
--散列分区表的散列分区接合 ALTER TABLE table_name COALESCE PARTITION; --散列分区表的散列子分区接合 ALTER TABLE table_name MODIFY PARTITION partition_name COALESCE SUBPARTITION;
7.重命名表分区
ALTER TABLE table_name RENAME PARTITION old_name TO new_name; ALTER TABLE table_name RENAME SUBPARTITION old_name TO new_name;
8.交换分区
- 1)三种单级分区与非分区表的交换
ALTER TABLE table_name EXCHANGE PARTITION partition_name WITH TABLE nonpartition_name;
- 2)单级散列分区表与复合*-散列分区的交换
- 3)复合*-散列分区中的散列子分区交换
- 4)单级列表分区表与复合*-列表分区的交换
- 5) 复合*-列表分区中的列表子分区交换
- 6)单级范围分区表与复合*-范围分区表的交换
- 7)复合*-范围分区中的范围子分区交换
9.移动分区
alter table custaddr move partition P_OTHER tablespace system; alter table custaddr move partition P_OTHER tablespace icd_service;
分区移动会自动维护局部分区索引,oracle不会自动维护全局索引,所以需要我们重新rebuild分区索引,具体需要rebuild哪些索引,可以通过dba_part_indexes,dba_ind_partitions去判断。
Select index_name,status From user_indexes Where table_name='CUSTADDR';
10.关于分区表和索引
- 1)本地分区索引
①本地前缀索引
- 2)全局分区索引
create index com_index_range_example_id on range_example(id);
2)建立本地分区索引
create index local_index_range_example_id on range_example(id) local;
3)建立全局分区索引
create index gidx_range_example_id on range_example(id) GLOBAL partition by range(id) ( part_01 values less than(1000), part_02 values less than(MAXVALUE) );
对于分区索引的删除,local index 不能指定分区名称,单独的删除分区索引。local index 对应的分区会伴随着data分区的删除而一起被删除。
global partition index 可以指定分区名称,删除某一分区。但是有一点要注意,如果该分区不为空,则会导致更高一级的索引分区被置为UNUSABLE 。
ALTER INDEX gidx_range_exampel_id drop partition part_01 ;
此句将导致part_02 状态为UNUSABLE
三 . 相关查询
1.跨分区查询
select sum( *) from (select count(*) cn from t_table_SS PARTITION (P200709_1) union all select count(*) cn from t_table_SS PARTITION (P200709_2) );
2.查询表上有多少分区
SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='tableName';
3.查询索引信息
select object_name,object_type,tablespace_name,sum(value) from v$segment_statistics where statistic_name IN ('physical reads','physical write','logical reads')and object_type='INDEX' group by object_name,object_type,tablespace_name order by 4 desc --显示数据库所有分区表的信息: select * from DBA_PART_TABLES --显示当前用户可访问的所有分区表信息: select * from ALL_PART_TABLES --显示当前用户所有分区表的信息: select * from USER_PART_TABLES --显示表分区信息 显示数据库所有分区表的详细分区信息: select * from DBA_TAB_PARTITIONS --显示当前用户可访问的所有分区表的详细分区信息: select * from ALL_TAB_PARTITIONS --显示当前用户所有分区表的详细分区信息: select * from USER_TAB_PARTITIONS --显示子分区信息 显示数据库所有组合分区表的子分区信息: select * from DBA_TAB_SUBPARTITIONS --显示当前用户可访问的所有组合分区表的子分区信息: select * from ALL_TAB_SUBPARTITIONS --显示当前用户所有组合分区表的子分区信息: select * from USER_TAB_SUBPARTITIONS --显示分区列 显示数据库所有分区表的分区列信息: select * from DBA_PART_KEY_COLUMNS --显示当前用户可访问的所有分区表的分区列信息: select * from ALL_PART_KEY_COLUMNS --显示当前用户所有分区表的分区列信息: select * from USER_PART_KEY_COLUMNS --显示子分区列 显示数据库所有分区表的子分区列信息: select * from DBA_SUBPART_KEY_COLUMNS --显示当前用户可访问的所有分区表的子分区列信息: select * from ALL_SUBPART_KEY_COLUMNS --显示当前用户所有分区表的子分区列信息: select * from USER_SUBPART_KEY_COLUMNS --怎样查询出oracle数据库中所有的的分区表 select * from user_tables a where a.partitioned='YES' --删除一个表的数据是 truncate table table_name; --删除分区表一个分区的数据是 alter table table_name truncate partition p5;