【发布时间】:2011-07-13 18:02:12
【问题描述】:
我一直试图弄清楚为什么对于记录表有几十万或更多记录的数据集,这个 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(记录:记录部分:记录人)
记录
- PK - sysid
- 物理标识
- 待定
- purge_in_progress
Record_Part
- PK - Part_pk
- FK - record_sysid
Record_Person
- PK - sysid
- FK - Part_pk
运行时
50000 条记录条目
- record_person forall 在 1:40 分钟内完成
- record_part forall 在 1:20 分钟内完成
- 记录在 10 秒内完成
300000 条记录条目
- record_person forall 在 9 分钟内完成
- record_part forall 在 2 小时内完成
- 记录在 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;
【问题讨论】:
-
您真的是一次将 200 万个元素收集到一个集合中,而不是每次都使用 LIMIT 来获取较少数量的元素吗?您是否跟踪会话以查看时间花费在哪里?如果是这样,您可以发布 tkprof 输出吗?
-
谢谢贾斯汀。我对批量收集的 rownum 限制运行脚本测试以获取运行时,但我想我没有考虑或意识到收集大小对执行速度的重要性。
-
不要使用 rownum 限制。在 BULK COLLECT 中使用 LIMIT 子句。
-
谢谢你,贾斯汀。您对提交频率的评论也很有帮助。