2

在我们的 Oracle 11g 数据库中,我们有一个表,它有一个主键 I_Node (int) 和一个名为 I_Parent_Node (int) 的列,它引用回同一表中的另一条记录。根节点的 I_Parent_Node = null。通过这种方式,我们形成了一个由节点、叶子、分支组成的树结构,无论您想如何称呼它们。

我们经常需要一次删除整个节点分支,这意味着一个节点及其所有子节点。有时这是很多很多的记录,比如 50,000 或更多。由于在自引用表上不允许级联删除,我们被迫从叶子开始逐个删除,然后沿着树的备份方式进行。我们经历了长达数小时的删除时间。

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

4

3 回答 3

1

您应该能够使用可延迟约束和分层查询来做到这一点。

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

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

如果当前不可延迟,则删除并重新创建您的外键:

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。

于 2012-04-10T21:05:01.880 回答
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 层次结构查询(按查询连接)来查询或遍历树。该表将非常薄(列不多,可能是这 3 个 + 一些修改日期),因此更新这些关系应该比弄乱主表要快得多,并且可以更好地扩展。

于 2012-04-10T18:56:18.410 回答
0

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

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

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

于 2012-04-11T02:25:49.297 回答