当前位置:Gxlcms > 数据库问题 > ORACLE 范围分区 partition-range分区

ORACLE 范围分区 partition-range分区

时间: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

人气教程排行