Oracle 分区表定义与修改

0. 前提说明:

  1. 默认情况下,oracle 的分区表对于分区字段不允许进行 update,对分区字段行进 update,就会报错——ORA-14402: 更新分区关键字列将导致分区的更改。但是可以通过打开表的 row movement 属性来允许对分区字段的 update 操作,不建议这么操作。
    2. 分区表尽量不要建主键,因为建主键的同时会建一个唯一性的全局索引,在 add/drop/truncate 分区表时如果不指定 update global indexes 则会使索引失效,导致数据无法插入。
    将主键建成本地索引方法:建一个包含 (分区列、主键列) 的唯一性复合索引,然后在这个索引上建主键
*   create unique index I_PCT_HISTORY_RECORD on PCT_HISTORY_RECORD (GID,create_date) local; #一定要包含分区列否则会报ORA-14039: 分区列必须构成 UNIQUE 索引的关键字列子集
*   alter table PCT_HISTORY_RECORD add primary key (GID,create_date);
*   alter table PCT_HISTORY_RECORD add primary key (GID,create_date) USING INDEX LOCAL;#创建索引与主键
  1. 全局索引在 drop partition、truncate partition 后都会失效,对于 Global index,Oracle 提供了一参数 update global indexes,可避免 truncate 或 drop partition 时索引失效问题,另外一种方法是 rebuild,这 2 种方法各有利弊,在生产上不同的环境方法也不一样,要平衡操作 ddl 的时间和重建索引哪个时间更少,以决定是否需要附加 update indexes 子句。
  • update global indexes,此种方法主要针对的是全局索引
  • rebuild,支持全局索引和本地索引
alter table test_partas truncate partition p0;
alter table test_partas drop partition p0;
alter index PK_ID rebuild online;
alter table test_partas truncate partition p1 update indexes;

1. 新建分区表

适用场景:环境初始化新建表,如果不存在删除分区的情况,可以和正常建表一样建立主键和全局唯一性索引,但普通索引字段建议走本地索引。

-- Create table

create table PCT_HISTORY_RECORD

(

gid VARCHAR2(32) not null,

code VARCHAR2(50),

name VARCHAR2(50),

is_publish NUMBER(1) default 0 not null,

remark VARCHAR2(200),

create_id VARCHAR2(32) not null,

create_date DATE default SYSDATE not null,

modify_id VARCHAR2(32),

modify_date DATE,

is_active NUMBER(1) default 0 not null,

is_delete NUMBER(1) default 0 not null,

uda1 VARCHAR2(50),

uda2 VARCHAR2(50),

uda3 VARCHAR2(50),

uda4 VARCHAR2(50),

uda5 VARCHAR2(50),

uda6 VARCHAR2(50),

uda7 VARCHAR2(50),

uda8 VARCHAR2(50),

uda9 VARCHAR2(50),

uda10 VARCHAR2(50),

deleted VARCHAR2(32),

data_role VARCHAR2(32) default -1 not null,

data_role1 VARCHAR2(32) default -1,

data_role2 VARCHAR2(32) default 0,

uda1c VARCHAR2(100),

uda1n VARCHAR2(100),

uda2c VARCHAR2(100),

uda2n VARCHAR2(100),

uda3c VARCHAR2(100),

uda3n VARCHAR2(100),

uda4c VARCHAR2(100),

uda4n VARCHAR2(100),

uda5c VARCHAR2(100),

uda5n VARCHAR2(100)

)

PARTITION BY RANGE(create_date)

INTERVAL(NUMTOYMINTERVAL(1,'MONTH'))

(

PARTITION P1_PCT_HISTORY_RECORD VALUES LESS THAN(TO_DATE('2019-01-01','YYYY-MM-DD'))

TABLESPACE PLATFORM_DATA

);

-- Add comments to the table

comment on table PCT_HISTORY_RECORD is 'PCT数据表';

-- Create/Recreate primary, unique and foreign key constraints:创建主键和索引

alter table PCT_HISTORY_RECORD add constraint PK_PCT_HISTORY_RECORD primary key (GID) using index tablespace PLATFORM_INDEX;

--创建唯一性本地索引,注意分区字段必须加上

create unique index I_PCT_HISTORY_RECORD on PCT_HISTORY_RECORD (GID,CREATE_DATE) tablespace PLATFORM_INDEX LOCAL;

-- 创建普通本地索引

create index I_PCT_HISTORY_RECORD_1 on PCT_HISTORY_RECORD (code) tablespace PLATFORM_INDEX LOCAL;

create index I_PCT_HISTORY_RECORD_2 on PCT_HISTORY_RECORD (is_publish) tablespace PLATFORM_INDEX LOCAL;

--如果不修改,新增的分区都会放到user表空间

alter table PCT_HISTORY_RECORD modify default attributes tablespace PLATFORM_DATA;

2. Oracle 普通表 -> 分区表,11g 在线重定义

适用场景:数据量百万或千万级,不能停服务的情况

  1. 环境准备:MES 正常表格定义,有主键,有索引,表空间与索引表空间随意,并准备好数据

– Create table

create table PCT_HISTORY_RECORD

(

gid VARCHAR2(32) not null,

code VARCHAR2(50),

name VARCHAR2(50),

is_publish NUMBER(1) default 0 not null,

remark VARCHAR2(200),

create_id VARCHAR2(32) not null,

create_date DATE default SYSDATE not null,

modify_id VARCHAR2(32),

modify_date DATE,

is_active NUMBER(1) default 0 not null,

is_delete NUMBER(1) default 0 not null,

uda1 VARCHAR2(50),

uda2 VARCHAR2(50),

uda3 VARCHAR2(50),

uda4 VARCHAR2(50),

uda5 VARCHAR2(50),

uda6 VARCHAR2(50),

uda7 VARCHAR2(50),

uda8 VARCHAR2(50),

uda9 VARCHAR2(50),

uda10 VARCHAR2(50),

deleted VARCHAR2(32),

data_role VARCHAR2(32) default -1 not null,

data_role1 VARCHAR2(32) default -1,

data_role2 VARCHAR2(32) default 0,

uda1c VARCHAR2(100),

uda1n VARCHAR2(100),

uda2c VARCHAR2(100),

uda2n VARCHAR2(100),

uda3c VARCHAR2(100),

uda3n VARCHAR2(100),

uda4c VARCHAR2(100),

uda4n VARCHAR2(100),

uda5c VARCHAR2(100),

uda5n VARCHAR2(100)

);

– Create/Recreate indexes

create index I_PCT_HISTORY_RECORD_1 on PCT_HISTORY_RECORD (CODE);

create index I_PCT_HISTORY_RECORD_2 on PCT_HISTORY_RECORD (is_publish);

– Create/Recreate primary, unique and foreign key constraints

alter table PCT_HISTORY_RECORD

add constraint PK_PCT_HISTORY_RECORD primary key (GID) using index ;

–插入随机数据

INSERT INTO PCT_HISTORY_RECORD(GID,CODE,NAME,IS_PUBLISH,REMARK,CREATE_ID,CREATE_DATE)

select sys_guid(),

dbms_random.string(‘A’, round(dbms_random.value(5,10))) CODE,

dbms_random.string(‘B’, round(dbms_random.value(5,10))) NAME,

1 AS IS_PUBLISH,

NULL AS REMARK,

‘ERIC’ AS CREATE_ID,

trunc(sysdate) - dbms_random.value(1, 365) create_date

from dual connect by rownum<=200000

  1. 创建重定义临时表,注意此处没有索引,主键等内容

create table PCT_HISTORY_RECORD_TEMP

(

gid VARCHAR2(32) not null,

code VARCHAR2(50),

name VARCHAR2(50),

is_publish NUMBER(1) default 0 not null,

remark VARCHAR2(200),

create_id VARCHAR2(32) not null,

create_date DATE default SYSDATE not null,

modify_id VARCHAR2(32),

modify_date DATE,

is_active NUMBER(1) default 0 not null,

is_delete NUMBER(1) default 0 not null,

uda1 VARCHAR2(50),

uda2 VARCHAR2(50),

uda3 VARCHAR2(50),

uda4 VARCHAR2(50),

uda5 VARCHAR2(50),

uda6 VARCHAR2(50),

uda7 VARCHAR2(50),

uda8 VARCHAR2(50),

uda9 VARCHAR2(50),

uda10 VARCHAR2(50),

deleted VARCHAR2(32),

data_role VARCHAR2(32) default -1 not null,

data_role1 VARCHAR2(32) default -1,

data_role2 VARCHAR2(32) default 0,

uda1c VARCHAR2(100),

uda1n VARCHAR2(100),

uda2c VARCHAR2(100),

uda2n VARCHAR2(100),

uda3c VARCHAR2(100),

uda3n VARCHAR2(100),

uda4c VARCHAR2(100),

uda4n VARCHAR2(100),

uda5c VARCHAR2(100),

uda5n VARCHAR2(100)

)PARTITION BY RANGE(create_date)

INTERVAL(NUMTOYMINTERVAL(1,‘MONTH’))

(

PARTITION P1_PCT_HISTORY_RECORD VALUES LESS THAN(TO_DATE(‘2019-01-01’,‘YYYY-MM-DD’))

TABLESPACE PLATFORM_DATA

) ;

–修改新增分区的默认表空间

alter table PCT_HISTORY_RECORD_TEMP modify default attributes tablespace PLATFORM_DATA;

  1. 开始重定义

  2. 确定是否可以重定义

EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(‘UNIMAX4_IMOM’,‘PCT_HISTORY_RECORD’);

  1. 开始重定义

EXEC DBMS_REDEFINITION.START_REDEF_TABLE(‘UNIMAX4_IMOM’,‘PCT_HISTORY_RECORD’,‘PCT_HISTORY_RECORD_TEMP’);

  1. 复制表对象属性 (例如触发器、索引等,此处没有执行),创建主键和索引

复制后原来的索引都是全局索引,就没有执行复制属性的操作。

DECLARE

error_count pls_integer := 0;

BEGIN

DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(

uname => ‘UNIMAX4_IMOM’,

orig_table => ‘PCT_HISTORY_RECORD’,

int_table => ‘PCT_HISTORY_RECORD_TEMP’,

ignore_errors => TRUE,

num_errors => error_count);

DBMS_OUTPUT.PUT_LINE(’errors := ’ || TO_CHAR(error_count));

END;

/

create unique index IDX_PCT_HISTORY_RECORD on PCT_HISTORY_RECORD_TEMP (GID,CREATE_DATE) tablespace PLATFORM_INDEX LOCAL;

create index IDX_PCT_HISTORY_RECORD_1 on PCT_HISTORY_RECORD_TEMP (code) tablespace PLATFORM_INDEX LOCAL;

create index IDX_PCT_HISTORY_RECORD_2 on PCT_HISTORY_RECORD_TEMP (is_publish) tablespace PLATFORM_INDEX LOCAL;

  1. 同步数据,对开始重定义后修改的数据执行同步

EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE (‘UNIMAX4_IMOM’,‘PCT_HISTORY_RECORD’,‘PCT_HISTORY_RECORD_TEMP’);

  1. 收集中间表的统计信息

EXEC DBMS_STATS.gather_table_stats(‘UNIMAX4_IMOM’, ‘PCT_HISTORY_RECORD_TEMP’, cascade => TRUE);

  1. 完成重定义

EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE(‘UNIMAX4_IMOM’,‘PCT_HISTORY_RECORD’,‘PCT_HISTORY_RECORD_TEMP’);

  1. 删除临时表

drop table PCT_HISTORY_RECORD_TEMP PURGE;

8. 修改索引,约束名称和原表一致

因为在创建索引时,索引名称没有加 TEMP,修改了索引的前缀,所以此处不重新调整索引名称。

  1. 在 FINISH_REDEF_TABLE 之前,可以使用 abort_redef_table 停止重定义,然后删除 PCT_HISTORY_RECORD_TEMP,如果不 Abort,删除不了

EXEC DBMS_REDEFINITION.ABORT_REDEF_TABLE (‘UNIMAX4_IMOM’,‘PCT_HISTORY_RECORD’,‘PCT_HISTORY_RECORD_TEMP’);

3. Oracle 普通表 -> 分区表,12c 在线重定义

适用场景:12c 的运行环境,但不确定索引会怎么处理

DBMS_REDEFINITION.REDEF_TABLE (

uname IN VARCHAR2,

tname IN VARCHAR2,

table_compression_type IN VARCHAR2 := NULL,

table_part_tablespace IN VARCHAR2 := NULL,

index_key_compression_type IN VARCHAR2 := NULL,

index_tablespace IN VARCHAR2 := NULL,

lob_compression_type IN VARCHAR2 := NULL,

lob_tablespace IN VARCHAR2 := NULL,

lob_store_as IN VARCHAR2 := NULL,

refresh_dep_mviews IN VARCHAR2 := ‘N’,

dml_lock_timeout IN PLS_INTEGER := NULL);

示例:

BEGIN

DBMS_REDEFINITION.REDEF_TABLE(

uname => ‘C##BB’,

tname => ‘T1’,

table_compression_type => NULL,

table_part_tablespace => ‘BB’,

index_key_compression_type => NULL,

index_tablespace => NULL,

lob_compression_type => NULL,

lob_tablespace => NULL,

lob_store_as => NULL);

END;

来源:https://blog.csdn.net/xxzhaobb/article/details/82182945

  1. Oracle 普通表 -> 分区表,停服务修改

适用场景:在线重定义的表数据量特别的大,可能过亿的数据量

来源:https://www.cnblogs.com/jyzhao/p/4378753.html

创建分区表,注意此处没有索引,主键等内容

create table PCT_HISTORY_RECORD_TEMP

(

gid VARCHAR2(32) not null,

code VARCHAR2(50),

name VARCHAR2(50),

is_publish NUMBER(1) default 0 not null,

remark VARCHAR2(200),

create_id VARCHAR2(32) not null,

create_date DATE default SYSDATE not null,

modify_id VARCHAR2(32),

modify_date DATE,

is_active NUMBER(1) default 0 not null,

is_delete NUMBER(1) default 0 not null,

uda1 VARCHAR2(50),

uda2 VARCHAR2(50),

uda3 VARCHAR2(50),

uda4 VARCHAR2(50),

uda5 VARCHAR2(50),

uda6 VARCHAR2(50),

uda7 VARCHAR2(50),

uda8 VARCHAR2(50),

uda9 VARCHAR2(50),

uda10 VARCHAR2(50),

deleted VARCHAR2(32),

data_role VARCHAR2(32) default -1 not null,

data_role1 VARCHAR2(32) default -1,

data_role2 VARCHAR2(32) default 0,

uda1c VARCHAR2(100),

uda1n VARCHAR2(100),

uda2c VARCHAR2(100),

uda2n VARCHAR2(100),

uda3c VARCHAR2(100),

uda3n VARCHAR2(100),

uda4c VARCHAR2(100),

uda4n VARCHAR2(100),

uda5c VARCHAR2(100),

uda5n VARCHAR2(100)

)PARTITION BY RANGE(create_date)

INTERVAL(NUMTOYMINTERVAL(1,‘MONTH’))

(

PARTITION P1_PCT_HISTORY_RECORD VALUES LESS THAN(TO_DATE(‘2019-01-01’,‘YYYY-MM-DD’))

TABLESPACE PLATFORM_DATA

) ;

–修改新增分区的默认表空间

alter table PCT_HISTORY_RECORD_TEMP modify default attributes tablespace PLATFORM_DATA;

  1. 设置新建分区表为 nologging, 重命名原表 T 为 T_OLD

alter table PCT_HISTORY_RECORD_TEMP nologging;

rename PCT_HISTORY_RECORD to PCT_HISTORY_RECORD_BAK;

  1. 并行直接路径插入 (10w 条数据 0.016 秒完成)

alter session enable parallel dml;

insert /*+ append parallel(p,10) / into PCT_HISTORY_RECORD_TEMP p select /+ parallel(n,10) */ * from PCT_HISTORY_RECORD_BAK n;

commit;

  1. 重命名历史表的索引和约束名

alter index PK_PCT_HISTORY_RECORD rename to PK_PCT_HISTORY_RECORD_BAK;

alter table PCT_HISTORY_RECORD_BAK rename constraint PK_PCT_HISTORY_RECORD to PK_PCT_HISTORY_RECOR_BAK;

alter index I_PCT_HISTORY_RECORD_1 rename to I_PCT_HISTORY_RECORD_1_BAK;

alter index I_PCT_HISTORY_RECORD_2 rename to I_PCT_HISTORY_RECORD_2_BAK;

4. 给新分区表 T_PART 创建主键及索引

alter table PCT_HISTORY_RECORD_TEMP add constraint PK_PCT_HISTORY_RECORD_TEMP primary key (GID) tablespace PLATFORM_INDEX LOCAL nologging parallel 32;

create index I_PCT_HISTORY_RECORD_1 on PCT_HISTORY_RECORD_TEMP (code) tablespace PLATFORM_INDEX LOCAL nologging parallel 32;

create index I_PCT_HISTORY_RECORD_2 on PCT_HISTORY_RECORD_TEMP (is_publish) tablespace PLATFORM_INDEX LOCAL nologging parallel 32;

  1. 修改索引和表为 logging,noparallel

alter index I_PCT_HISTORY_RECORD_1 logging noparallel;

alter index I_PCT_HISTORY_RECORD_2 logging noparallel;

alter table PCT_HISTORY_RECORD_TEMP logging;

6.rename 表,恢复 T 表的相关应用

rename PCT_HISTORY_RECORD_TEMP to PCT_HISTORY_RECORD;

4. 分区表模拟创建随机数据

create table test as

select sys_guid(),

dbms_random.string(‘A’, round(dbms_random.value(5,10))) M1,

dbms_random.string(‘B’, round(dbms_random.value(5,10))) M2,

dbms_random.string(‘C’, round(dbms_random.value(5,10))) M3,

ROUND(dbms_random.value(5,10),4) N1,

ROUND(dbms_random.value(5000,10000)) N2,

rownum seq,

trunc(sysdate) - dbms_random.value(1, 365) create_date

from dual connect by rownum<=200000