Oracle如何归档引用分区表

Posted

技术标签:

【中文标题】Oracle如何归档引用分区表【英文标题】:Oracle how to archive reference partitioned table 【发布时间】:2019-09-19 14:49:16 【问题描述】:

我正在尝试将数据从间隔分区的父表和按引用分区的子表移动到相应的存档表结构中。

令我惊讶的是,这个看似简单的任务却超出了我的能力范围......

我已经阅读了moving partitioned table to archive,但它没有说明如何使用外键移动表格。

我也读到了moving reference partitioned tables,但是这个解决方案对我不起作用,在第一个语句之后给出了这个错误:

ORA-02266:表中的唯一/主键被启用的外键引用

所以,我尝试了自己的方法。它给了我更严重的错误:

ORA-00600: 内部错误代码,参数:[kkpamRefGet: index], [], [], [], [], [], [], [], [], [], [], [ ]

你可以像这样重现我最近的尝试:

/*
DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
*/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
    PARTITION_DATE DATE NOT NULL,
    PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(  
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
    PK NUMBER NOT NULL,
    FK_PARENT NUMBER NOT NULL,
    CONSTRAINT FK_CHILD_TABLE
    FOREIGN KEY (FK_PARENT) 
    REFERENCES PARENT_TABLE (PK)
    ON DELETE CASCADE
    ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
    PARTITION_DATE DATE NOT NULL,
    PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(  
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
    PK NUMBER NOT NULL,
    FK_PARENT NUMBER NOT NULL,
    CONSTRAINT FK_CHILD_TABLE_ARCHIVE
    FOREIGN KEY (FK_PARENT) 
    REFERENCES PARENT_TABLE_ARCHIVE (PK)
    ON DELETE CASCADE
    ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
-- My last attempt to do this
ALTER TABLE CHILD_TABLE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting: ORA-14130: UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting:  ORA-14128: FOREIGN KEY constraint mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT) 
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
/
-- And here is something starange...
ALTER TABLE CHILD_TABLE_ARCHIVE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/

目前,我不知道该怎么做,我开始想知道我是否应该尝试将此结构移动到存档...它按日期分区,所以我可以让它增长吗?

我将不胜感激在这件事上的任何帮助。 :)

更新:

正如Francisco 建议的那样,CASCADE 选项有助于我的示例代码。以下是我在工作状态下的示例代码。

但是,在我的现实生活场景中,父表不止一个孩子。因此,当我尝试使用 CASCDe 选项时,我得到ORA-14706。建议的解决方案是不使用 CASCADE 选项...

所以我仍然无法归档我的表格,并且仍然需要帮助。

DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
    PARTITION_DATE DATE NOT NULL,
    PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(  
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
    PK NUMBER NOT NULL,
    FK_PARENT NUMBER NOT NULL,
    CONSTRAINT FK_CHILD_TABLE
    FOREIGN KEY (FK_PARENT) 
    REFERENCES PARENT_TABLE (PK)
    ON DELETE CASCADE
    ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
    PARTITION_DATE DATE NOT NULL,
    PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(  
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
    PK NUMBER NOT NULL,
    FK_PARENT NUMBER NOT NULL,
    CONSTRAINT FK_CHILD_TABLE_ARCHIVE
    FOREIGN KEY (FK_PARENT) 
    REFERENCES PARENT_TABLE_ARCHIVE (PK)
    ON DELETE CASCADE
    ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT) 
REFERENCES PARENT_TABLE_TMP (PK)
ENABLE VALIDATE
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/

【问题讨论】:

您有 Oracle 支持许可证吗?如果是这样,this looks like the Note you need to read。 (我自己没有许可证,所以我不能保证笔记的有效性。) 不,我没有。 为什么首先要将分区表中的数据移动到存档表中?一旦引入分区而不将数据移出表外,我能想到的几乎所有存档表用例都有相应的解决方案。除非您对不使用分区键的表进行查询并且必须扫描每个分区? 是的,我有这样的疑问。 注释提到在交易所使用级联选项,例如:ALTER TABLE <parent> EXCHANGE PARTITION FOR (to_date('19-MAY-2018','dd-MON-yyyy')) WITH TABLE <exchange_table> cascade update indexes;你试过了吗? 【参考方案1】:
-----creating reference partitioning on existing tables having parent child relationship


----------------------------------------consider the following parent and child table---------------------------------------------------
--create the parent table:

create table t1(
  id int,
  action_date   varchar(8),
  constraint t1_pk primary key (id)
);

--create the child table table:
create table t2(
  id int,
  id_t1,
  constraint t2_pk primary key (id),
  constraint t2_fk1 foreign key (id_t1) references t1(id)
);


---insert sample data into parent
insert into t1 values(1,'20170801');
insert into t1 values(2,'20170901');
insert into t1 values(3,'20171001');

---insert sample data into child
insert into t2 values(1,1);
insert into t2 values(2,1);
insert into t2 values(3,1);
insert into t2 values(4,2);
insert into t2 values(5,1);
insert into t2 values(6,2);
insert into t2 values(7,3);



---------------------------------------------------------creating intermediate table for partitioning-----------------------------------------------------------------
-----------------parent table-------------------------
create table t1_part(
  id int,
  action_date   varchar(8),
  constraint t1_part_pk primary key (id)
) PARTITION BY RANGE (action_date)
    (
        PARTITION t1_part_old VALUES LESS THAN ('20171101'),
        PARTITION t1_part_201711 VALUES LESS THAN ('20171201'),
        PARTITION t1_part_201712 VALUES LESS THAN ('20180101'),
    PARTITION t1_part_def VALUES LESS THAN ('99999999')
  );

-------------------dropping constraints-----------------
ALTER TABLE t2 DROP constraint t2_fk1;  
ALTER TABLE t1 DROP constraint t1_pk;
ALTER TABLE t1_part DROP constraint t1_part_pk;

desc t1;
desc t1_part;

-------------------------switch parent data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_old WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_def WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;

--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);


ALTER TABLE t1_part add constraint t1_part_pk primary key (id);
--select * from t1_part;

drop table t1;
RENAME t1_part TO t1;
ALTER TABLE t1 RENAME CONSTRAINT t1_part_pk TO t1_pk;
ALTER TABLE t2 add constraint t2_fk1 foreign key (id_t1) references t1(id);  

--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);

----------------------create partitioned child table---------------------------------------------
create table t2_part(
  id int,
  id_t1 not null,
  constraint t2_part_pk primary key (id),
  constraint t2_part_fk1 foreign key (id_t1) references t1(id)
) partition by reference (t2_part_fk1);

alter table t2 modify (id_t1 int not null);

desc t2;
desc t2_part

-------------------------switch child data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_old WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_def WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;


--select * from t2_part;
drop table t2;
RENAME t2_part TO t2;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_pk TO t2_pk;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_fk1 TO t2_fk1;

--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T2', cascade => TRUE);

-----------------------------------check partition info---------------------------------------------
select table_name, partition_name, high_value
from user_tab_partitions
where table_name in ('T1','T2');

desc t1;
desc t2;
-----------------add new parent partition, child partiion will automatically get created thorugh reference paritioning through foreign key t2_part_fk1
ALTER TABLE T1 SPLIT PARTITION t1_part_old AT ('20170701') INTO (PARTITION t1_part_old, PARTITION t1_part_201707) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201707 AT ('20170801') INTO (PARTITION t1_part_201707, PARTITION t1_part_201708) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201708 AT ('20170901') INTO (PARTITION t1_part_201708, PARTITION t1_part_201709) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201709 AT ('20171001') INTO (PARTITION t1_part_201709, PARTITION t1_part_201710) UPDATE GLOBAL INDEXES;

EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);

--------------------validating the partitioned data--------------------

select count(*) from T1 partition (T1_PART_OLD);
select * from T1 partition (T1_PART_201708);
select count(*) from T1 partition (T1_PART_201709);
select count(*) from T1 partition (T1_PART_201710);
select count(*) from T1 partition (T1_PART_201711);


select * from T2;
select * from T1;


select count(*) from T2 partition (T1_PART_OLD);
select * from T2 partition (T1_PART_201708);
select count(*) from T2 partition (T1_PART_201709);
select count(*) from T2 partition (T1_PART_201710);
select count(*) from T2 partition (T1_PART_201711);

-------truncate the partition T1_PART_201708 (refering the parent partition) and validate the data
alter table t2 truncate partition T1_PART_201708;
select * from t2;       ----------------- data from 20170801 to 20170831 will be truncated from child

-------truncate the parent record
alter table t1 drop partition T1_PART_201708;
select * from t1;

【讨论】:

一步一步将已有的父子关系表转换为引用分区 您好,谢谢您的回答,但我认为这不是我问题的答案 - 我不想分区,未分区的表。我想将数据从分区表移动到具有相同结构的分区存档表中。 :) 所以,在你的例子结束时,我们有我想移动到另一个表的结构,例如 t1_arch、t2_arch。 :)

以上是关于Oracle如何归档引用分区表的主要内容,如果未能解决你的问题,请参考以下文章

如何监控linux阿里云磁盘空间

ORACLE 大表索引问题:数据量5亿+,做查询,按时间一个月分区,查询会用到3 4个字段,如何见索引

Oracle分区表

oracle 11g 新增分区

oracle recyclebin详解

100天精通Oracle-实战系列(第24天)Oracle 数据泵表导出导入