时间:2021-07-01 10:21:17 帮助过:13人阅读
语法如下:
column:分区依赖列(如果是多个,以逗号分隔);
partition:分区名称;
values less than:后跟分区范围值(如果依赖列有多个,范围对应值也是多个,以逗号分隔开);
tablespace_clause:分区的存储属性,例如所在表空间等属性(可为空),默认继承基表所有表空间的属性。
Range Partition Example
SQL> edit
已写入 file afiedt.buf
1 create table t_partition_range(id number,name varchar2(20))
2 partition by range(id)(
3 partition p1 values less than(10),
4 partition p2 values less than(20),
5 partition p3 values less than(30),
6 partition pmax values less than(maxvalue)
7* )
SQL> /
表已创建。
通过数据字典“user_part_tables记录分区表的信息”,“user_tab_partitions记录表分区的信息”可查询创建分区的信息。。
例如:
SQL> select table_name,partitioning_type,partition_count
2 from user_part_tables where table_name=‘T_PARTITION_RANGE‘;
TABLE_NAME PARTITI PARTITION_COUNT
------------------------------ ------- ---------------
T_PARTITION_RANGE RANGE 4
SQL> set linesize 200
SQL> column partition_name format a20;
SQL> column high_value format 999;
SQL> column tablespace_name format a30;
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name=‘T_PARTITION_RANGE‘
3* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
PMAX MAXVALUE JJJG
2、range分区表上创建索引
2.1、创建global索引range分区:
SQL> edit
已写入 file afiedt.buf
1 create index idx_parti_range_id on t_partition_range(id)
2 global partition by range(id)(
3 partition i_p1 values less than(10),
4 partition i_p2 values less than(20),
5 partition i_p3 values less than(30),
6* partition i_pmax values less than(maxvalue))
SQL> /
索引已创建。
由上例可以看出,创建 global 索引的分区与创建表的分区语句格式完全相同,而且其分区形式与索引 所在表的分区形式没有关联关系。
注:上例是range分区表创建range分区的 global索引,并不表示range分区表只能创建range分区global索引,也可创建hash分区的global索引。
查询索引的分区信息可通过user_part_indexes,user_ind_partitions两个数据字典。
2.2、创建Local分区索引
SQL> create index idx_parti_range_id on t_partition_range(id) local;
索引已创建。
SQL> select index_name,partitioning_type,partition_count
2 from user_part_indexes
3 where index_name=‘IDX_PARTI_RANGE_ID‘;
INDEX_NAME PARTITI PARTITION_COUNT
------------------------------ ------- ---------------
IDX_PARTI_RANGE_ID RANGE 4
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_ind_partitions
3 where index_name=‘IDX_PARTI_RANGE_ID‘
4* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
PMAX MAXVALUE JJJG
可以看出, local 索引的分区完全继承表的分区的属性,包括分区类型,分区的范围值即不需指定也不
能更改,即local 索引的分区维护完全依赖于其索引所在表,不过分区名称及分区所在的表空间是可以自定义的,如下:
SQL> create index IDX_PART_RANGE_ID ON T_PARTITION_RANGE(id) local (
2 partition i_range_p1 tablespace tbspart01,
3 partition i_range_p2 tablespace tbspart01,
4 partition i_range_p3 tablespace tbspart02,
5 partition i_range_pmax tablespace tbspart02
6 );
3、分区表的管理
3.1、增加表分区(add partition)
增加表分区,适用于所有分区形式,语法为alter table tbname add partition……
值得注意的是像list,range这种存在范围值的分区,所要增加的分区值必须大于当前分区中的最大值(如果当前存在maxvalue或default的
分区,add partition会报错,这种情况只能使用spilt),hash分区则无此限制。
例如:
SQL> alter table t_partition_range add partition p4 values less than(40);
alter table t_partition_range add partition p4 values less than(40)
*
第 1 行出现错误:
ORA-14074: 分区界限必须调整为高于最后一个分区界限。
如前面所说,range分区存在maxvalue时,add partition会报错,下面我们先进行分区拆分。
3.2、拆分表分区(split partition)
split partition即将一个分区拆分成二个,其用途非常广泛,如通常发现一个分区过大,就可以将其分解成多个分区,常最见的还是
split maxvalue/default的分区。
该命令的语法针对不同分区会有不同形式,
For range partition : alter table tbname split partition ptname at (value) into (partition newpt1
tbs_clause,partition newpt2 tbs_clause);
For list partition : alter table tbname split partition ptname values (v1,v2...vn) into (partition newpt1
tbs_clause,partition newpt2 tbs_clause);
上述两项,如果是操作子分区,则将 partition 关键字换成 subpartition 即可。旧分区中符合新定义值的
记录会存储到指定的第一个分区中,其它的记录存储到第二个分区。
例:
查询表现有分区
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name=‘T_PARTITION_RANGE‘
3* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
PMAX MAXVALUE JJJG
对range分区表的maxvalue分区进行拆分
SQL> alter table t_partition_range split partition pmax at(40) into(
2 partition p4 ,partition pmax);
表已更改。
拆分后,查询表分区如下
SQL> select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name=‘T_PARTITION_RANGE‘
3 order by partition_position;
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
P4 40 JJJG
PMAX MAXVALUE JJJG
即小于40的存放p4分区,其它存放pmax分区。
提示:
1、split partition/subpartition 不能用于 hash 分区或 hash 子分区 (hash 的话,直接用 add partition 就好 了 )
2、split partition/subpartition 视被分隔的分区数据量多少,可能需要花费不小的代价,相当于该分区数据的全扫描,我们也许可以形容为: full partition scan:) ,除非:
Split 后的两个分区中,至少有一个是空的,并且非空的那个分区的存储属性与 split 前的存储属性完全相同 。
如果 split 的分区包含 lob 字段, split 后非空的那个分区中该字段的存储属性也必须与 split 前 的存储属性完全相同。
这种情况下的 split partition/subpartition 也会非常高效, oracle 会自动进行优化,此时的分区操作类 似于 add partition 。
通常情况下,如果在执行 split partition/subpartition 时,如果没有指定 update indexes 子句,都会造成 local 和 global 索引的失效。注意,我们说的是通常,如果你 split partition/subpartition 的是个空分区, 或 者没有触发任何数据移动或变化,那么即使不加 update indexes ,也不会影响到索引。当然,保险起见,建议你还是执行完之后,查询一下数据字典,确认一下当前索引的状态。
3.3、删除表分区(drop partition)
删除表分区包含两种操作,分别是:
删除分区:alter table[tablename] drop partition[ptname];
删除子分区:alter table[tablename] drop subpartition[ptname];
除hash分区和hash子分区外,其它分区格式都可以支持这项操作。
例:删除上面split partition添加的p4分区
SQL> alter table t_partition_range drop partition p4;
表已更改。
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name=‘T_PARTITION_RANGE‘
3* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
PMAX MAXVALUE JJJG
注意:删除分区时,该分区内存储的数据也将同时删除。
由于是ddl操作,这种删除比较迅速,因此如果你确认某个分区的数据都要被删除,使用drop partition会比delete更高效,
如果你的本意是希望删除掉指定分区但保留数据,你应该使用merge partition,接下来就会讲到。
同样,如果你在执行该语句时没有指定 update indexes 子句,也会导致 global 索引的失效,至于 local 索引嘛,删除分区时对应的索引分区会被同时删除,但其它分区的local 索引不会受到影响。
3.4、合并表分区(merge partitions)
合并二个分区成一个分区,适用于除hash分区之外的所有分区形式(hash分区此功能用coalesce partition收缩表分区 代替)
语法: alter table tbname merge partitions/subpartitions pt1,pt2 into partition/subpartition pt3;
同样也支持 update indexes 子句以避免单独执行造成索引失效的问题。
注意,要合并的两个分区必须是连续的,合并分区操作不会造成数据丢失,另外如果想为新分区指定属性,在语句末尾处可增加存储属性(
如果不指定,则新分区默认继续表的存储属性)。
例:
--range分区表 t_partition_range先split pmax分区,即新增p4分区
SQL> edit
已写入 file afiedt.buf
1 alter table t_partition_range split partition pmax at(40) into (
2* partition p4,partition pmax)
SQL> /
表已更改。
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name=‘T_PARTITION_RANGE‘
3* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
P4 40 JJJG
PMAX MAXVALUE JJJG
--执行merge partition操作
SQL> edit
已写入 file afiedt.buf
1 alter table t_partition_range merge partitions p4,pmax into
2* partition pmax
SQL> /
表已更改。
--查看合并后表分区情况
SQL> edit
已写入 file afiedt.buf
1 select partition_name,high_value,tablespace_name
2 from user_tab_partitions
3 where table_name=‘T_PARTITION_RANGE‘
4* order by partition_position
SQL> /
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------------------------------------------------------------------
P1 10 JJJG
P2 20 JJJG
P3 30 JJJG
PMAX MAXVALUE JJJG
3.5、交换表分区(Exchange Partitions)
Exchange Partitions就是迁移数据。其 提供了一种方式,让你在表与表或分区与分区之间迁移数据,注意不是将表转换成
分区或非分区的形式,而仅只是迁移表中数据 ( 互相迁移 ) ,由于其号称是采用了更改数据字典的方式,因此效率最高 ( 几乎不涉及 io 操作 ) 。 Exchange partition 适用于所有分区格式,你可以将数据从分区表迁移到非分区表,也可以从非分区表迁移至分区表,或者从 hash partition 到 range partition 诸如此类吧。
其语法很简单: alter table tbname1 exchange partition/subpartition ptname with table tbname2;
例:先给t_partition_range表插入几条数据。
SQL> insert into t_partition_range values(11,‘a‘);
已创建 1 行。
SQL> insert into t_partition_range values(12,‘b‘);
已创建 1 行。
SQL> insert into t_partition_range values(13,‘c‘);
已创建 1 行。
SQL> commit;
提交完成。
SQL> select * from t_partition_range;
ID NAME
---------- --------------------
11 a
12 b
13 c
--创建非分区表,结构与t_partition_range表相同
SQL> create table t_partition_range_tmp(id number,name varchar2(50));
表已创建。
SQL> edit
已写入 file afiedt.buf
1 alter table t_partition_range exchange partition p2
2* with table t_partition_range_tmp
SQL> /
alter table t_partition_range exchange partition p2
*
第 1 行出现错误:
ORA-14097: ALTER TABLE EXCHANGE PARTITION 中的列类型或大小不匹配
--交换失败,因表结构列类型不同,查看二表结构
SQL> desc t_partition_range;
名称 是否为空? 类型
----------------------------------------------------------------------------------- -------- ------
ID NUMBER
NAME VARCHAR2(20)
SQL> desc t_partition_range_tmp;
名称 是否为空? 类型
----------------------------------------------------------------------------------- -------- ------
ID NUMBER
NAME VARCHAR2(50)
--修改t_partition_range_tmp表name字段长度
SQL> alter table t_partition_range_tmp modify name varchar2(20);
表已更改。
SQL> alter table t_partition_range exchange partition p2
2 with table t_partition_range_tmp;
表已更改。
SQL> select * from t_partition_range;
未选定行
SQL> select * from t_partition_range_tmp;
ID NAME
---------- --------------------
11 a
12 b
13 c
--执行exchange partition,交换数据
SQL> alter table t_partition_range exchange partition p2
2 with table t_partition_range_tmp;
表已更改。
SQL> select * from t_partition_range;
ID NAME
---------- --------------------
11 a
12 b
13 c
SQL> select * from t_partition_range_tmp;
未选定行
--t_partition_range_tmp插入数据,包含t_partition_range 非p2分区的数据
SQL> insert into t_partition_range_tmp values(14,‘d‘);
已创建 1 行。
SQL> insert into t_partition_range_tmp values(9,‘e‘);
已创建 1 行。
SQL> insert into t_partition_range_tmp values(31,‘f‘);
已创建 1 行。
SQL> commit;
提交完成。
SQL> select * from t_partition_range;
ID NAME
---------- --------------------
11 a
12 b
13 c
SQL> select * from t_partition_range_tmp;
ID NAME
---------- --------------------
14 d
9 e
31 f
--再次执行exchange partition
SQL> alter table t_partition_range exchange partition p2
2 with table t_partition_range_tmp;
with table t_partition_range_tmp
*
第 2 行出现错误:
ORA-14099: 未对指定分区限定表中的所有行
--交换失败,因为 t_partition_range_tmp表中值9,31不在 t_partition_range表中p2分区内,附加without validation可交换成功
SQL> alter table t_partition_range exchange partition p2
2 with table t_partition_range_tmp without validation;
表已更改。
SQL> select * from t_partition_range partition(p2);
ID NAME
---------- --------------------
14 d
9 e
31 f
SQL> select * from t_partition_range_tmp;
ID NAME
---------- --------------------
11 a
12 b
13 c
--删除交换后的 t_partition_range表中非p2分区内的值9,31,竟然删除0行。
SQL> delete from t_partition_range where id in(9,31);
已删除0行。
--指定9,31数值查询也查不到
SQL> select * from t_partition_range where id in(9,31);
未选定行
--指定p2分区查询能查出来
SQL> select * from t_partition_range partition(p2);
ID NAME
---------- --------------------
14 d
9 e
31 f
--直接对表做delete操作,记录可全删除
SQL> delete from t_partition_range;
已删除3行。
SQL> rollback;
回退已完成。
SQL> delete from t_partition_range where id=9;
已删除0行。
SQL> delete from t_partition_range where id=14;
已删除 1 行。
SQL> rollback;
回退已完成。
注意:
1、涉及交换的两表之间表结构必须一致,除非附加 with validation 子句 ;
2、如果是从非分区表向分区表做交换,非分区表中的数据必须符合分区表中指定分区的规则,除非 附加 without validation 子句 ,交换后,分区表中指定交换的分区数据含有不符合该分区定义的数据,这些数据无法直接删除或查找(如上例内容所示)。
3、如果从分区表向分区表做交换,被交换的分区的数据必须符合分区规则,除非附加 without validation 子句 ;
Global 索引或涉及到数据改动了的 global 索引分区会被置为 unusable ,除非附加 update indexes 子 句。
提示:
一旦附加了 without validation 子句,则表示不再验证数据有效性,因此指定该子句时务必慎重。
3.6、截断表分区(Truncate Partition)
Truncate partition 就像 truncate table 一样,直接从头部截断数据,用来删除数据那是效率超高无比。 但 是如果该表有外键引用的话,
ddl 的 truncate 就不好使了,只能要么使用delete ,要么先disable掉外键关联再truncate 了。同样,在不指定 update indexes 子句的情况下, truncate partition 也会造成分区所在表的 global索引失效。
语法非常简单: alter table tbname truncate partition/subpartition ptname;
例:
SQL> select * from t_partition_range partition(p2);
ID NAME
---------- --------------------
11 a
12 b
13 c
SQL> alter table t_partition_range truncate partition p2;
表被截断。
SQL> select * from t_partition_range partition(p2);
未选定行
3.7、移动表分区(Move partition)
Move partition 与 modify partition 的功能相似,但又比之更加强劲,比如可以修改分区所在表空间等等 , 与 move table 的操作很类似,某些时间也非常有用,比如降低行迁移。另外,move partition修改分区所在表空间时,分区对应的local索引表空间不会被修改。
语法很简单: Alter table tbname move partition/subpartition ptname .....;
SQL> select partition_name,tablespace_name from user_tab_partitions
2 where table_name=‘T_PARTITION_RANGE‘;
PARTITION_NAME TABLESPACE_NAME
-------------------- --------------------
P1 JJJG
P2 JJJG
P3 JJJG
PMAX JJJG
SQL> alter table t_partition_range move partition p3 tablespace jjjg_data;
表已更改。
SQL> select partition_name,tablespace_name from user_tab_partitions
2 where table_name=‘T_PARTITION_RANGE‘;
PARTITION_NAME TABLESPACE_NAME
-------------------- --------------------
P1 JJJG
P2 JJJG
P3 JJJG_DATA
PMAX JJJG
SQL> edit
已写入 file afiedt.buf
1 select partition_name,tablespace_name from user_ind_partitions
2* where index_name=‘IDX_PARTI_RANGE_ID‘
SQL> /
PARTITION_NAME TABLESPACE_NAME
-------------------- --------------------
P1 JJJG
P2 JJJG
P3 JJJG
PMAX JJJG
提示: move partition/subpartiton 时会锁表,并且 move partition/subpartiton 视被移动分区中数据量的多 少,会带来相应的 IO 操作。同时还需要注意,如果在 move partition/subpartiton 时没有指定 update indexes 子句,则被移动分区所在的 local 索引以及全局索引都会失效,需要手工 rebuilding 。
3.8、重命名表分区(Rename Partition)
就是改名,跟表改名,列改名类似,语法很简单:
alter table tbname rename patition ptname to newptname;
例:
SQL> select partition_name,tablespace_name from user_tab_partitions
2 where table_name=‘T_PARTITION_RANGE‘;
PARTITION_NAME TABLESPACE_NAME
-------------------- --------------------
P1 JJJG
P2 JJJG
P3 JJJG
PMAX JJJG
SQL> alter table t_partition_range rename partition p3 to p4;
表已更改。
SQL> select partition_name,tablespace_name from user_tab_partitions
2 where table_Name=‘T_PARTITION_RANGE‘;
PARTITION_NAME TABLESPACE_NAME
-------------------- --------------------
P1 JJJG
P2 JJJG
P4 JJJG
PMAX JJJG
ORACLE 范围分区 partition-range分区
标签:partition by range