如何在Oracle中为自引用表改进删除时间

时间:2012-04-10 18:29:26

标签: oracle performance cascading-deletes

在我们的Oracle 11g数据库中,我们有一个表,它有一个主键I_Node(int),还有一个名为I_Parent_Node(int)的列,它引用了同一个表中的另一个记录。根节点具有I_Parent_Node = null。通过这种方式,我们形成了节点,叶子,分支的树结构,无论你想要什么叫它们。

我们经常需要一次删除整个节点分支,这意味着节点及其所有子节点。有时这是很多很多记录,比如50,000或更多。由于在自引用表上不允许级联删除,因此我们不得不从叶子开始一个接一个地删除并按照树的方式进行操作。我们经历了数小时的删除时间。

我们正在考虑进行“删除标记”技术,其中一个单独的程序会在非高峰时段清除标记为删除的节点,但我对数据库设计更改或其他Oracle构造是否有帮助感兴趣在这里。除了我在工作中学到的东西之外,我没有接受过Oracle培训,创建数据库的人并没有考虑到这么大的数量。我对数据库设计的变化持开放态度,因为它还不是一个固定的设计。

3 个答案:

答案 0 :(得分:1)

您可能需要考虑将层次结构与主表分开。所以你的主表只有主要ID(让我们称之为“ID”),你的层次表将有“ID,ParentID,TreeID”。 ParentID是ID的父节点,TreeID是树中的最高父节点(级别1)。

因此,1级节点看起来像:

ID, ParentID, TreeID 
1, [null], 1

2级节点如下所示:

ID, ParentID, TreeID
2, 1, 1

3级节点如下所示:

ID, ParentID, TreeID
3, 2, 1

等等。

您可以使用Oracle hierarchy queries(按查询连接)来查询或遍历树。这个表格非常薄(不是很多列,这些3 +一些修改日期可能),所以更新这些关系应该比乱用主表更快,更好。

答案 1 :(得分:1)

您应该能够使用可延迟约束和分层查询来执行此操作。

如果您的外键约束(在I_Parent_Node上)尚未推迟,请将其删除并使用关键字“DEFERRABLE”重新创建它。

这是一个使用Oracle示例中的EMPLOYEES表的示例(我修改了DEPARTMENTS表,以便执行此操作,但实际上并不需要示例):

Drop&如果您的外键当前不可延迟,请重新创建外键:

alter table employees drop constraint emp_manager_fk;
alter table employees add constraint emp_manager_fk foreign key (manager_id) references employees(employee_id) deferrable;

在您的交易中,推迟您的约束,并使用分层查询删除:

set constraints all deferred; 

delete
from     employees e
where    employee_id in (select   employee_id
                         from     employees
                         start with employee_id = 108
                         connect by prior employee_id = manager_id);

“108”是我“父母”记录的ID。

答案 2 :(得分:0)

我假设您已经完成了标准调整 - 即节点和父节点ID列是否适合索引?

(1)问题的一种方法是使用PL / SQL。批量收集要删除的ID,使用首先返回叶子行的分层查询到数组中;然后使用数组进行批量删除(FORALL)。

(2)另一种方法是软删除 - 将行标记为“已删除”,但实际上从未删除它们。您需要修改应用程序(或使用Oracle VPD自动忽略查询中的“已删除”行)。如果删除节点相对较少,这可能会相当有效;但如果您经常删除大量节点,那么这会使表格混乱很多旧数据。