sqlplus / as sysdba
create tablespace PAR;
create user par identified by par;
grant dba to par;
创建测试表:
sqlplus par/par
create table lucifer(id number(8) PRIMARY KEY,
name varchar2(20) not null,
par_date date)
tablespace PAR;
comment on table lucifer is 'lucifer表';
comment on column lucifer.name is '姓名';
comment on column lucifer.par_date is '分区日期';
create index id_name on lucifer(name) tablespace par;
插入测试数据:
sqlplus par/par
begin
foriin0..24 loop
insert into lucifer values
(i,
'lcuifer_'|| i,
add_months(to_date('2021-1-1', 'yyyy-mm-dd'), i));
end loop;
commit;
end;
/
可以看到,测试数据已经构建完成,接下来开始实战操作。
2、查看是否能够重定义
需提前确认表是否有主键,表空间是否足够:
sqlplus / as sysdba
##查看主键select cu.* from user_cons_columns cu, user_constraints au where cu.constraint_name = au.constraint_name and au.constraint_type ='P' and au.table_name ='LUCIFER';
确认是否可以重定义,没有主键用 rowid:
sqlplus / as sysdba
exec dbms_redefinition.can_redef_table('PAR', 'LUCIFER');
create table lucifer_par
(id NUMBER(8),
name VARCHAR2(20),
par_date DATE
)
partition BY RANGE(par_date)(
partition lucifer_P202101 values less than (TO_DATE(' 2021-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202102 values less than (TO_DATE(' 2021-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202103 values less than (TO_DATE(' 2021-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202104 values less than (TO_DATE(' 2021-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202105 values less than (TO_DATE(' 2021-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202106 values less than (TO_DATE(' 2021-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202107 values less than (TO_DATE(' 2021-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202108 values less than (TO_DATE(' 2021-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202109 values less than (TO_DATE(' 2021-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202110 values less than (TO_DATE(' 2021-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202111 values less than (TO_DATE(' 2021-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202112 values less than (TO_DATE(' 2022-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202201 values less than (TO_DATE(' 2022-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202202 values less than (TO_DATE(' 2022-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202203 values less than (TO_DATE(' 2022-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202204 values less than (TO_DATE(' 2022-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202205 values less than (TO_DATE(' 2022-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202206 values less than (TO_DATE(' 2022-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202207 values less than (TO_DATE(' 2022-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202208 values less than (TO_DATE(' 2022-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202209 values less than (TO_DATE(' 2022-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202210 values less than (TO_DATE(' 2022-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202211 values less than (TO_DATE(' 2022-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_P202212 values less than (TO_DATE(' 2023-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) tablespace par,
partition lucifer_MAX values less than (maxvalue) tablespace par)enable row movement
tablespace par;
如上,唯一索引和约束不加,会自动复制,分区表结构的中间表已经生成。
4、检查中间表是否开启行迁移
select row_movement from dba_tables where table_name='LUCIFER' and owner='PAR';select row_movement from dba_tables where table_name='LUCIFER_PAR' and owner='PAR';
5、收集表统计信息
为了确保数据准确,开始前进行统计信息收集:
sqlplus / as sysdba
exec dbms_stats.gather_table_stats(ownname =>'PAR',tabname =>'LUCIFER',estimate_percent =>10,method_opt=>'for all indexed columns',cascade=>TRUE,degree =>'8');exec dbms_stats.gather_table_stats(ownname =>'PAR',tabname =>'LUCIFER_PAR',estimate_percent =>10,method_opt=>'for all indexed columns',cascade=>TRUE,degree =>'8');
6、开始在线重定义
sqlplus / as sysdba
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('PAR','LUCIFER','LUCIFER_PAR');
sqlplus / as sysdba
ALTER index PAR.ID_NAME RENAME TO ID_NAME_BAK;
rename新分区表索引,由于新分区表的索引名称还是中间表的索引名称,所以需要手动rename:
sqlplus / as sysdba
ALTER index PAR.ID_NAME_PAR RENAME TO ID_NAME;
15、查看是否存在无效索引
sqlplus / as sysdba
SELECT owner index_owner, index_name, index_type,'N/A' partition_name,status,table_name,tablespace_name,
'alter index '||owner||'.'||index_name||' rebuild;' rebuild_index
FROM dba_indexes
WHERE status ='UNUSABLE'
UNION ALL
SELECT a.index_owner,a.index_name,b.index_type,a.partition_name,a.status,b.table_name,a.tablespace_name,
'alter index '||a.index_owner||'.'||a.index_name||' rebuild partition '||a.partition_name||' ;' rebuild_index
FROM dba_ind_partitions a, dba_indexes b
WHERE a.index_name = b.index_name
AND a.index_owner = b.owner
AND a.status ='UNUSABLE'
UNION ALL
SELECT owner index_owner,a.index_name,b.index_type,'N/A' partition_name,a.status,b.table_name,NULL,
'alter index '||a.index_owner||'.'||a.index_name||' rebuild subpartition '||a.subpartition_name||';' rebuild_index
FROM dba_ind_subpartitions a, dba_indexes b
WHERE a.index_name = b.index_name
AND a.index_owner = b.owner
AND a.status ='UNUSABLE';
16、检查切换后是否开启row_movement
sqlplus / as sysdba
select owner,table_name,row_movement from dba_tables where table_name in('LUCIFER','LUCIFER_PAR') and owner='PAR';
17、检查无效对象
##无效对象编译
sqlplus / as sysdba
@?/rdbms/admin/utlrp.sql
select'alter '||object_type||' '||owner||'.'||object_name||' compile;'
from dba_objects t
where t.status ='INVALID' order by 1;
18、收集统计信息
sqlplus / as sysdba
exec dbms_stats.gather_table_stats(ownname =>'PAR',tabname =>'LUCIFER',estimate_percent =>10,method_opt=>'for all indexed columns',cascade=>TRUE,degree =>'8');
19、插入测试数据
sqlplus par/par
begin
foriin100..124 loop
insert into lucifer values
(i,
'lcuifer_'|| i,
add_months(to_date('2021-5-1', 'yyyy-mm-dd'), i));
end loop;
commit;
end;
/
20、查询分区表数据分布
sqlplus par/par
SELECT COUNT(*) FROM LUCIFER;
SELECT * FROM LUCIFER PARTITION(LUCIFER_P202101);
SELECT * FROM LUCIFER PARTITION(LUCIFER_P202201);
SELECT * FROM LUCIFER PARTITION(LUCIFER_MAX);
可以发现,数据已经根据日期均匀分布在不同的子分区中。至此,在线重定义已经完成,分区表已成功转换。
参考MOS文档:
How To Partition Existing Table Using DBMS_REDEFINITION (Doc ID 472449.1)