Partition Tables介绍及分区表转换

--====================数据库

-- Partition Tablessession

--====================less

分区表相关概念:性能

当表数据不断增长时,查询数据库速度就回变慢,应用程序性能就会降低,这个时候就该考虑对表进行分区管理。分区表在逻辑上任然是一张完整的表,只是在物理上可能存放在多个表空间或物理文件上。当查询数据是,不至于每次都扫描整张表,避免热块争用。这样比全表扫描能提供更好的数据处理能力和访问能力。大数据

 

限制条件:ui

1. 簇表不适用与分区spa

2. 不能分割含有LONG,LOG RAW字段的表日志

3. 索引朱指标(IOT)表不能进行范围分区。orm

 

分区表优势:索引

1. 加强可用性:

2. 减小关闭时间

3.可维护性

4.均衡I/O

5.提升性能

6.对应用,用户透明

 

分区表类别:

1. 范围分区 range partition

2. 哈希分区 hash partition

3. 列表分区 list partition

4. 引用分区 reference partition

5. 复合分区 composite partition

6. 间隔分区 interval partition

7. 系统分区

 

相关视图:

select partitioning_type,table_name,interval from user_part_tables

select table_name,partition_name,tablespace_name,interval from user_tab_partitions;

select partitioned,owner,table_name from dba_tables;

显示子分区信息,dba_tab_subpartitions

显示分区列 dba_part_key_columns

显示子分区列 dba_subpart_key_columns

 

分区转换方法:

1. 导入导出 (imp/impdp)

2. 子查询(subquery )

3. 分区转发 partition exchange

4. 在线重定义 dbms_redefinition

 

1.1 Export/import method

采用逻辑导出导入很简单,首先在源库创建分区表,而后将数据导出,而后导入到新建的分区表便可,

1)  导出表:

expdp \'/ as sysdba\' directory=DATA_PUMP_DIR dumpfile=lhr_t.dmp  INCLUDE=TABLE:\"IN \(\'T\'\)\" SCHEMAS=LHR LOGFILE=expdp_T.log

2)  删除表:drop table numbers;

3)  重建分区表的定义:

    create table numbers (qty number(3), name varchar2(15))

    partition by range (qty)

    (partition p1 values less than (501),

     partition p2 values less than (maxvalue));

4)  利用ignore=y来导入分区表:

impdp \'/ as sysdba\' directory=DATA_PUMP_DIR dumpfile=lhr_t.dmp SCHEMAS=LHR table_exists_action=APPEND LOGFILE=impdp_T.log

5) 查询导入后的状况

SYS@dlhr> SELECT D.TABLE_OWNER,D.TABLE_NAME,D.PARTITION_NAME FROM DBA_TAB_PARTITIONS d WHERE d.table_name='T';

 

2.1 利用原表重建分区表(插入)

这种方法的特色是:

优势:方法简单易用,因为采用DDL语句,不会产生UNDO,且只产生少许REDO,效率相对较高,并且建表完成后数据已经在分布到各个分区中了。

不足:对于数据的一致性方面还须要额外的考虑。因为几乎没有办法经过手工锁定T表的方式保证一致性,在执行CREATE TABLE语句和RENAME T_NEW TO T语句直接的修改可能会丢失,若是要保证一致性,须要在执行完语句后对数据进行检查,而这个代价是比较大的。另外在执行两个RENAME语句之间执行的对T的访问会失败。

 适用于修改不频繁的表,在闲时进行操做,表的数据量不宜太大。

 

主要有2种方式,ctas和insert方式,下边分别介绍:

2.1.1  例一:CTAS+RENAME

利用CTAS语法在建立分区表的时候能够一块儿插入数据,也能够建立好表结构再insert 进去。 CTAS这种方法采用DDL语句,不产生UNDO,只产生少许REDO,建表完成后数据已经在分布到各个分区中。

模拟环境:

SQL> create table part1 (id number, time date);

表已建立。

 

SQL> insert into part1 select rownum,created from dba_objects;

已建立72807行。

 

SQL> commit;

提交完成。

 

SQL> select to_char(time,'yyyymmdd'),count(1) from part1 group by to_char(time,'yyyymmdd');

 

TO_CHAR(TIME,'YY COUNT(1)

---------------- ----------

20180323 39

20180324 39

20180326 39

20180321 4414

20180330 42

20180322 20

20180331 72

20180325 39

20180327 39

20100330 68018

20180329 46

 

已选择11行。

 

SQL> create table t_new (id,time) partition by range(time)(

2 partition t1 values less than(to_date('20180323','yyyymmdd')),

3 partition t2 values less than(to_date('20180324','yyyymmdd')),

4 partition t3 values less than(to_date('20180325','yyyymmdd')),

5 partition t4 values less than(to_date('20180326','yyyymmdd')),

6 partition t5 values less than(to_date('20180329','yyyymmdd')),

7 partition t6 values less than (maxvalue)) as select id,time from part1;

 

表已建立。

注意:若是表数据量分厂,如上方法是很是损耗性能的,固然咱们可使用添加‘并行DDL’,‘加nologging’和‘查询并行’方式来提升转换性能。

 

SQL> create table t_new (id,time) partition by range(time)(

2 partition t1 values less than(to_date('20180323','yyyymmdd')),

3 partition t2 values less than(to_date('20180324','yyyymmdd')),

4 partition t3 values less than(to_date('20180325','yyyymmdd')),

5 partition t4 values less than(to_date('20180326','yyyymmdd')),

6 partition t5 values less than(to_date('20180329','yyyymmdd')),

7 partition t6 values less than (maxvalue))

as select /*+parallel*/ id,time from part1;

 

2.1.2  例二: Insert with a subquery method

这种方法就是先创建表结构而后使用insert 来实现。

建立分区表:

LHR@dlhr> CREATE TABLE T_LHR_20160527_NEW (ID NUMBER, TIME DATE)

  2  PARTITION BY RANGE (TIME)

  3      (PARTITION T1 VALUES LESS THAN (TO_DATE('201311', 'YYYYMM')),

  4       PARTITION T2 VALUES LESS THAN (TO_DATE('201606', 'YYYYMM')),

  5       PARTITION T3 VALUES LESS THAN (MAXVALUE));

 

从源表查询插入到新表中:

LHR@dlhr> alter table T_LHR_20160527_NEW nologging;

 

Table altered.

 

LHR@dlhr> alter session enable parallel dml;

 

Session altered.

 

LHR@dlhr> insert /*+APPEND PARALLEL*/ into T_LHR_20160527_NEW (ID, TIME) select /*+PARALLEL(t3,4)*/  * from T_LHR_20160527;

注意:采用并行DML必须执行alter session enable parallel dml;

 

3.1  使用交换分区的方法(Partition exchange method)

这种方法的特色

 优势:只是对数据字典中分区和表的定义进行了修改,没有数据的修改或复制,效率最高。若是对数据在分区中的分布没有进一步要求的话,实现比较简单。在执行完RENAME操做后,能够检查T_OLD中是否存在数据,若是存在的话,直接将这些数据插入到T中,能够保证对T插入的操做不会丢失。

不足:仍然存在一致性问题,交换分区以后RENAME T_NEW TO T以前,查询、更新和删除会出现错误或访问不到数据。若是要求数据分布到多个分区中,则须要进行分区的SPLIT操做,会增长操做的复杂度,效率也会下降。

转换以后,原表上的索引,约束须要从新创建。

 适用于包含大数据量的表转到分区表中的一个分区的操做。应尽可能在闲时进行操做。

3.1.1 模拟环境:

SQL> create table obj as select object_name,object_id,created from user_objects;

SQL> alter table obj add constraint obj_idx primary key(object_id);

已建立72807行。

建立分区:

create table obj_range(

object_name varchar2(128) ,

object_id number ,

created date,

constraint obj_indx primary key(object_id))

partition by range(created)(

partition r1 values less than(to_date('2018/06/01','yyyy/mm/dd')) tablespace p1,

partition r2 values less than(to_date('2018/07/01','yyyy/mm/dd')) tablespace p2,

partition r3 values less than(maxvalue));

 

表已建立。

 

注意:若是是单分区,须要r1分区包含转换的表obj的全部数据,否则会报错误:

第 1 行出现错误:

ORA-14099: 未对指定分区限定表中的全部行

 

转换数据:

SQL> alter table obj_range exchange partition r1 with table obj;

 

Table altered.

 

SQL> alter index SH.OBJ_INDX rebuild online;

 

Index altered.

 

SQL> insert into obj_range values('obj',100,to_date('2018/05/21','yyyy/mm/dd'));

 

1 row created.

 

查看分区信息:

SQL> select table_name,PARTITION_NAME,SUBPARTITION_COUNT,TABLESPACE_NAME from user_tab_partitions where table_name='OBJ_RANGE';

 

在数据转换的时候很难保证有新数据插入,因此在转换完成以后须要对老表数据查询看是否有新数据存在,有的话直接掺入到新分区表中。

若是要求数据分布到多个分区中,则须要进行分区的SPLIT操做。

原表跟分区表字段类型,长度,约束要保持一致。

转换的分区表名字改为跟老表同样。

 

3.1.2. 若是分区表存在多个分区,就须要对分区进行单独转换

交换分区的操做步骤以下:

     1. 建立分区表,假设有2个分区,P1,P2.

     2. 建立表A存放P1规则的数据。

     3. 建立表B 存放P2规则的数据。

     4. 用表A 和P1 分区交换。 把表A的数据放到到P1分区

     5. 用表B 和p2 分区交换。 把表B的数据存放到P2分区。

SQL> alter table part exchange partition SAL1 with table sh.sales1;

 

Table altered.

 

SQL> alter table part exchange partition SAL2 with table sh.sales2;

 

Table altered.

 

 

 

4.1 利用在线重定义功能(DBMS_REDEFINITION)

这种分区的特色

优势:保证数据的一致性,在大部分时间内,表T均可以正常进行DML操做。只在切换的瞬间锁表,具备很高的可用性。这种方法具备很强的灵活性,对各类不一样的须要都能知足。并且,能够在切换前进行相应的受权并创建各类约束,能够作到切换完成后再也不须要任何额外的管理操做。

 不足:实现上比上面两种略显复杂。

 适用于各类状况。

在线重定义的大体操做流程以下:

       (1)建立基础表A(数据表),若是存在,就不须要操做。

       (2)建立临时的分区表B结构。

       (3)开始重定义,将基表A的数据导入临时分区表B。

       (4)结束重定义,完成后在DB的 Name Directory里,已经将2个表进行了交换。即此时基表A成了分区表,咱们建立的临时分区表B 成了普通表。 此时咱们能够删除咱们建立的临时表B。它已是普通表。

4.1.2 在线重定义功能

这个功能只在9.2.0.4之后的版本才有,在线重定义表具备如下功能:

       (1)修改表的存储参数;

       (2)将表转移到其余表空间;

       (3)增长并行查询选项;

       (4)增长或删除分区;

       (5)重建表以减小碎片;

       (6)将堆表改成索引组织表或相反的操做;

       (7)增长或删除一个列。

4.1.3在线重定义表的步骤

在线重定义的原理:物化视图

在线重定义表的步骤:

1.选择一种重定义方法:

存在两种重定义方法,一种是基于主键、另外一种是基于ROWID。ROWID的方式不能用于索引组织表(IOT),并且重定义后会存在隐藏列M_ROW$$。默认采用主键的方式。

2.调用DBMS_REDEFINITION.CAN_REDEF_TABLE()过程,若是表不知足重定义的条件,将会报错并给出缘由。

3.在用一个方案中创建一个空的中间表,根据重定义后你指望获得的结构创建中间表。好比:采用分区表,增长了COLUMN等。

4.调用DBMS_REDEFINITION.START_REDEF_TABLE()过程,并提供下列参数:被重定义的表的名称、中间表的名称、列的映射规则、重定义方法。

若是映射方法没有提供,则认为全部包括在中间表中的列用于表的重定义。若是给出了映射方法,则只考虑映射方法中给出的列。若是没有给出重定义方法,则认为使用主键方式。

5.在中间表上创建触发器、索引和约束,并进行相应的受权。任何包含中间表的完整性约束应将状态置为disabled。

当重定义完成时,中间表上创建的触发器、索引、约束和受权将替换重定义表上的触发器、索引、约束和受权。中间表上disabled的约束将在重定义表上enable。

6.(可选)若是在执行DBMS_REDEFINITION.START_REDEF_TABLE()过程和执行DBMS_REDEFINITION.FINISH_REDEF_TABLE()过程直接在重定义表上执行了大量的DML操做,那么能够选择执行一次或屡次的SYNC_INTERIM_TABLE()过程,以减小最后一步执行FINISH_REDEF_TABLE()过程时的锁定时间。

7.执行DBMS_REDEFINITION.FINISH_REDEF_TABLE()过程完成表的重定义。这个过程当中,原始表会被独占模式锁定一小段时间,具体时间和表的数据量有关。

执行完FINISH_REDEF_TABLE()过程后,原始表重定义后具备了中间表的属性、索引、约束、受权和触发器。中间表上disabled的约束在原始表上处于enabled状态。

8.(可选)能够重命名索引、触发器和约束。对于采用了ROWID方式重定义的表,包括了一个隐含列M_ROW$$。推荐使用下列语句经隐含列置为UNUSED状态或删除。

ALTER TABLE TABLE_NAME SET UNUSED (M_ROW$$);

ALTER TABLE TABLE_NAME DROP UNUSED COLUMNS;

 

4.1.4 使用在线重定义的限制条件

使用在线重定义的一些限制条件:

(1) There must be enough space to hold two copies of the table.

(2) Primary key columns cannot be modified.

(3) Tables must have primary keys.

(4) Redefinition must be done within the same schema.

(5) New columns added cannot be made NOT NULL until after the redefinition operation.

(6) Tables cannot contain LONGs, BFILEs or User Defined Types.

(7) Clustered tables cannot be redefined.

(8) Tables in the SYS or SYSTEM schema cannot be redefined.

(9) Tables with materialized view logs or materialized views defined on them cannot be redefined.

(10) Horizontal sub setting of data cannot be performed during the redefinition.

?若是使用基于主键的方式,则原表后重定义后的表必须有相同的主键

?  若是使用基于ROWID的方式,则不能是索引组织表

?  若是原表上有物化视图或者物化视图日志,则不能在线重定义

?  物化视图容器表或者高级队列表不能在线重定义

?  索引组织表的溢出表不能在线重定义

?  拥有BFILE,LOGN列的表不能在线重定义

?  Cluster中的表不能在线重定义

?  sys和system下的表不能在线重定义

?  临时表不能在线重定义

?  不支持水平数据子集

?  在列映射时只能使用有肯定结果的表达式,如子查询就不行

?  若是中间表有新增列,则不能有NOT NULL约束

?  原表和中间表之间不能有引用完整性

?  在线重定义没法采用nologging

 

4.1.5 模拟环境:

 

SQL> create table obj(id number, time date);

表已建立。

SQL> insert into obj select rownum,created from dba_objects;

 

已建立72820行。

 

SQL> commit;

 

提交完成。

 

SQL> create index date_idx on obj(time);

 

索引已建立。

SQL> exec dbms_stats.gather_table_stats('PLAT','OBJ',cascade=>true);

 

PL/SQL 过程已成功完成。

 

建立临时分区表:

create table obj_range(

object_name varchar2(128) ,

object_id number ,

created date,

constraint obj_indx primary key(object_id))

partition by range(created)(

partition r1 values less than(to_date('2018/06/01','yyyy/mm/dd')) tablespace p1,

partition r2 values less than(to_date('2018/07/01','yyyy/mm/dd')) tablespace p2,

partition r3 values less than(maxvalue));

 

表已建立。

 

表合法性检查:检查是否能够执行在线重定义,若返回错误的话说明不能执行,须要根据提示修改表

SQL> exec dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_use_pk);

BEGIN dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_us

e_pk); END;

 

*

第 1 行出现错误:

ORA-12089: 不能联机从新定义无主键的表 "PLAT"."OBJ"

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 139

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 1782

ORA-06512: 在 line 1

 

SQL> alter table plat.OBJ add constraint idx_pk primary key (id);

 

表已更改。

 

SQL> exec dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_use_pk);

 

PL/SQL 过程已成功完成。

 

开始在线重定义:

SQL> exec dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE',dbms_redef

inition.cons_use_pk);

BEGIN dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE',dbms_redefinit

ion.cons_use_pk); END;

 

*

第 1 行出现错误:

ORA-42016: 中间表的形式与指定的列映射不匹配

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 52

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 1646

ORA-06512: 在 line 1

 

表列映射:

SQL> exec dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE','id id,time created_date ',dbms_redefinition.cons_use_pk);

PL/SQL 过程已成功完成。

 

SQL> select count(1) from OBJ;

 

COUNT(1)

----------

72821

 

SQL> select count(1) from OBJ_RANGE;

 

COUNT(1)

----------

72820

 

 

由上可见基表多一条数据,颇有多是在进行表在线重定义的时候,基表有数据插入,这个时候咱们须要让基表数据跟中间表同步

SQL> exec dbms_redefinition.sync_interim_table('PLAT','OBJ','OBJ_RANGE');

 

PL/SQL 过程已成功完成。

相关文章
相关标签/搜索