我一直试图弄清楚为什么这个 PL/SQL 清除脚本对于记录表有几十万或更多记录的数据集运行缓慢。在脚本执行之前,记录表的某个子集被标记为清除 - 大约 75%。
是什么导致 Record_Part 表的删除比其他表花费的时间长得多?是不是因为它位于 3-table 父子层次结构的中间?我是否在索引或约束方面错过了一些知识?我可以做些什么来加快这个定期清除过程?
这是一个 Oracle 10g 数据库。
提前感谢您阅读我的问题。
架构(部分):
- 记录表是父表
- Record_Part 表是Record 的子表(Record 有很多Record_Part)
- Record_Person 是 Record_Part 的子项(Record_Part 有多个 Record_Person)
- 典型比例为 1:7:9 (record:record_part:record_person)
记录
- PK-系统ID
- 物理标识
- 待办的
- purge_in_progress
记录_部分
- PK - Part_pk
- FK-record_sysid
Record_Person
- PK-系统ID
- FK - Part_pk
运行时
50000 条记录条目
- record_person forall 在 1:40 分钟内完成
- record_part forall 在 1:20 分钟内完成
- 记录 forall 在 10 秒内完成
300000 条记录条目
- record_person forall 在 9 分钟内完成
- record_part forall 在 2 小时内完成
- 记录 forall 在 20 分钟内完成
2000000 条记录条目
- record_person forall 在 1 小时内完成
- record_part forall 在 13 小时内完成 (!)
- 记录在 8 分钟内完成
索引和约束 DDL
alter table Record add constraint record_REC_PK primary key (SYSID) using index tablespace DB_INDEX1;
alter table Record_Part add constraint RECPART_REC_PK primary key (Part_PK) using index tablespace DB_INDEX1;
alter table Record_Part add constraint RECPART_FK foreign key (RECORD_SYSID) references record (SYSID);
alter table Record_Person add constraint RECPERSON_REC_PK primary key (SYSID) using index tablespace DB_INDEX1;
alter table Record_Person add constraint RECPERSON_FK foreign key (Part_PK) references Record_Part (Part_PK);
CREATE INDEX REC_PURGE_IDX ON record (PURGE_IN_PROGRESS);
CREATE INDEX REC_PHYSID_IDX ON record (PHYSICALID);
CREATE INDEX REC_PENDING_IDX ON record (PENDING);
CREATE INDEX RECPART_RECORD_SYSID_IDX ON Record_Part (RECORD_SYSID);
CREATE INDEX RECPERSON_PARTPK_IDX on Record_Person (PART_PK);
脚本:( 下面的脚本省略了时间戳打印)
DECLARE
TYPE sSysid IS TABLE OF record.sysid%TYPE
INDEX BY PLS_INTEGER;
TYPE physicalid IS TABLE OF record.physicalid%TYPE
INDEX BY PLS_INTEGER;
l_sid sSysid;
l_physicalid physicalid;
BEGIN
SELECT sysid, physicalid
BULK COLLECT INTO l_sid, l_physicalid
FROM record
where purge_in_progress = 1;
FORALL i IN l_sid.FIRST .. l_sid.LAST
delete from record_person where Part_pk like concat(l_sid(i), '%') or Part_pk like concat(l_physicalid(i), '%');
commit;
FORALL i IN l_sid.FIRST .. l_sid.LAST
delete from record_Part where record_sysid = l_sid(i);
commit;
FORALL i IN l_sid.FIRST .. l_sid.LAST
delete from record where sysid = l_sid(i);
END;
/
commit;