1、概念:

分区表:当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下降,这时就应该考虑对表进行分区。表进行分区后,逻辑上表仍然是一张完整的表,只是将表中的数据在物理上存放到多个表空间(物理文件上),这样查询数据时,不至于每次都扫描整张表。

 Oracle的分区表可以包括多个分区,每个分区都是一个独立的段(SEGMENT),可以存放到不同的表空间中。查询时可以通过查询表来访问各个分区中的数据,也可以通过在查询时直接指定分区的方法来进行查询。

 

2、分区的类型:

(1)范围分区(range)
(2)哈希分区(hash)
(3)列表分区(list)
(4)范围-哈希复合分区(range-hash)
(5)范围-列表复合分区(range-list)

 3、示例:

a、Partition exchange method:

 1、查看数据:

SELECT to_char(begintime,'yyyy') YEAR,count(*) FROM nmgdx_nopart group by to_char(begintime,'yyyy');

YEAR COUNT(*)
201201 32736
201202 30624
201203 16736

2、创建表:
此表结构与原表一样。
-- Create table
create table NMGDX_PART
(
  begintime       DATE not null,
  endtime         DATE not null,
  city_id         VARCHAR2(16) not null,
  city_name       VARCHAR2(32),
  ap_num          NUMBER,
  available_num   NUMBER,
  unavailable_num NUMBER,
  available_rate  NUMBER,
  is_day          NUMBER(1)
)
tablespace MBWBASEDATA
partition by range(begintime)
(partition aprate values less than (maxvalue))

---partition p01 values less than (to_date('201201','yyyymm'),

---partition p02 values less than (to_date('201202','yyyymm'),


3、交换分区:
交换两分区表的数据
alter table nmgdx_part exchange partition aprate with table nmgdx_nopart;


SELECT to_char(begintime,'yyyy'),count(*) FROM nmgdx_part group by to_char(begintime,'yyyy');

YEAR COUNT(*)
201201 32736
201202 30624
201203 16736

SELECT to_char(begintime,'yyyy'),count(*) FROM nmgdx_nopart group by to_char(begintime,'yyyy');
no rows selected


4、拆分分区aprate:
alter table nmgdx_part split partition aprate at (to_date('201201','yyyymm')) into (partition P_201201,partition aprate);
alter table nmgdx_part split partition aprate at (to_date('201202','yyyymm')) into (partition P_201202 ,partition aprate);
alter table nmgdx_part split partition aprate at (to_date('201213','yyyymm')) into (partition P_201203,partition aprate);
alter table nmgdx_part split partition aprate at (to_date('201204','yyyymm')) into (partition P_201204,partition aprate);

5、创建索引:
create index aprate_idx on nmgdx_nopart(begintime) local;

6、重命名分区:

alter table nmgdx_nopart rename to nmgdx_nopart_bak;
alter table nmgdx_part rename to nmgdx_nopart;

7、查询验证:
SELECT count(*) FROM nmgdx_nopart partition(P_201202);

    COUNT(*)
1 32736

SELECT count(*) FROM nmgdx_nopart partition(P_201202);

    COUNT(*)
1 30624

SELECT count(*) FROM nmgdx_nopart partition(P_201203);

    COUNT(*)
1 16736

 b、Export/import method

1、导出表::
exp wipnms1/wipnms1 tables=nmgdx_test file=c:\exp.dmp
此处注意客户端版本要与服务器一致,否则报以下错:
EXP-00008: 遇到 ORACLE 错误 904 ORA-00904: "MAXSIZE": invalid identifier
详细参阅:
http://blog.csdn.net/johnstrive/article/details/5660729

2、drop 表:
drop table nmgdx_test purge;

3、创建分区表:
-- Create table
create table NMGDX_test
(
  begintime       DATE not null,
  endtime         DATE not null,
  city_id         VARCHAR2(16) not null,
  city_name       VARCHAR2(32),
  ap_num          NUMBER,
  available_num   NUMBER,
  unavailable_num NUMBER,
  available_rate  NUMBER,
  is_day          NUMBER(1)
)
partition by range(begintime)
(
partition P01 values less than(to_date('2012-02-01','yyyy-mm-dd')),
partition P02 values less than(to_date('2012-04-01','yyyy-mm-dd')),
partition P03 values less than(maxvalue));

4、导入数据:
imp wipnms1/wipnms1 file=exp.dmp ignore=y

c、Insert with a subquery method

1)  创建分区table:
create table NMGDX_CS
(
  begintime       DATE not null,
  endtime         DATE not null,
  city_id         VARCHAR2(16) not null,
  city_name       VARCHAR2(32),
  ap_num          NUMBER,
  available_num   NUMBER,
  unavailable_num NUMBER,
  available_rate  NUMBER,
  is_day          NUMBER(1)
)
partition by range(begintime)
(
partition P01 values less than(to_date('2012-02-01','yyyy-mm-dd')),
partition P02 values less than(to_date('2012-04-01','yyyy-mm-dd')),
partition P03 values less than(maxvalue));


2)  接数据插入到分区表中:

insert into nmgdx_cs select * from nmgdx_test;

d、DBMS_REDEFINITION

在线重定义的大致操作流程如下:
(1)创建基础表A,如果存在,就不需要操作。
(2)创建临时的分区表B。
(3)开始重定义,将基表A的数据导入临时分区表B。
(4)结束重定义,此时在DB的 Name Directory里,已经将2个表进行了交换。即此时基表A成了分区表,我们创建的临时分区表B 成了普通表。 此时我们可以删除我们创建的临时表B。它已经是普通表。

---http://gaoqinqing.blog.163.com/blog/static/47020022011618102610551/

--创建基本表和索引

create table nmgdx_test (
id number(10),
crate_date date,
name varchar2(100)
);

alter table nmgdx_test ADD (CONSTRAINT nmgdx_test PRIMARY KEY (id));
create index create_date_ind on nmgdx_test(crate_date);
INSERT INTO nmgdx_test SELECT ROWNUM,created,object_name FROM Dba_Objects;

--收集表的统计信息
exec dbms_stats.gather_table_stats('wipnms1','nmgdx_test',cascade=>true);

--创建临时分区表
create table nmgdx_cs (
id number(10),
crate_date date,
name varchar2(100)
)
PARTITION BY RANGE(crate_date)
(
PARTITION p001 VALUES LESS THAN(to_date('200912','yyyymm')),
PARTITION p002 VALUES LESS THAN(to_date('201012','yyyymm')),
PARTITION p003 VALUES LESS THAN(to_date('201112','yyyymm')),
PARTITION p004 VALUES LESS THAN(to_date('201212','yyyymm')),
PARTITION p005 values less than(maxvalue));

---进行重定义操作
----检查重定义的合理性
EXEC Dbms_Redefinition.can_redef_table('wipnms1','nmgdx_test');

PL/SQL procedure successfully completed.


---开始重定义,分区表和原表列名相同
begin
dbms_redefinition.start_redef_table(
uname=>'wipnms1',
orig_table=>'nmgdx_test',
int_table=>'nmgdx_cs');
end;
/

--如果分区表的列名和原表不一致,那么在开始重定义的时候,需要重新指定映射关系:
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(
'wipnms1',
'unpar_table',
'par_table',
'ID ID, create_date TIME', -- 在这里指定新的映射关系
DBMS_REDEFINITION.CONS_USE_PK);


---同步新表
begin
dbms_redefinition.sync_interim_table(
uname=>'wipnms1',
orig_table=>'nmgdx_test',
int_table=>'nmgdx_cs');
end;
/

---创建索引,在线重定义只重定义数据,索引还需要单独建立

create index create_date_ind2 on nmgdx_cs(crate_date);


--收集新表的统计信息
exec dbms_stats.gather_table_stats('wipnms1','nmgdx_cs',cascade=>true);

---结束重定义
begin
dbms_redefinition.finish_redef_table(
uname=>'wipnms1',
orig_table=>'nmgdx_test',
int_table=>'nmgdx_cs');
end;
/

---结束重定义的意义:
       --基表unpar_table 和临时分区表par_table 进行了交换。 此时临时分区表par_table成了普通表,我们的基表unpar_table成了分区表。
       --我们在重定义的时候,基表unpar_table是可以进行DML操作的。 只有在2个表进行切换的时候会有短暂的锁表。

--- 删除临时表
DROP TABLE nmgdx_cs;

---索引重命名
ALTER INDEX create_date_ind2 RENAME TO create_date_ind;

--验证
select partitioned from user_tables where lower(table_name) = 'nmgdx_test';
  par
1 YES

select partition_name from user_tab_partitions where lower(table_name) = 'nmgdx_test';
1 P005
2 P004
3 P003
4 P002
5 P001