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

如何改进Oracle中自引用表的删除时间,oracle,performance,cascading-deletes,Oracle,Performance,Cascading Deletes,在Oracle 11g数据库中,我们有一个表,其中有一个主键I_节点(int),还有一个名为I_Parent_节点(int)的列,该列引用同一表中的另一条记录。根节点的I_Parent_node=null。通过这种方式,我们形成了一个由节点、叶子、分支组成的树结构 我们经常需要一次删除整个节点分支,这意味着一个节点及其所有子节点。有时这是很多很多记录,比如50000或更多。由于不允许对自引用表进行级联删除,因此我们必须从叶子开始逐个删除,并以返回树的方式进行删除。我们经历了数小时长的删除时间 我

在Oracle 11g数据库中,我们有一个表,其中有一个主键I_节点(int),还有一个名为I_Parent_节点(int)的列,该列引用同一表中的另一条记录。根节点的I_Parent_node=null。通过这种方式,我们形成了一个由节点、叶子、分支组成的树结构

我们经常需要一次删除整个节点分支,这意味着一个节点及其所有子节点。有时这是很多很多记录,比如50000或更多。由于不允许对自引用表进行级联删除,因此我们必须从叶子开始逐个删除,并以返回树的方式进行删除。我们经历了数小时长的删除时间


我们正在考虑采用“标记删除”技术,在非高峰时间,单独的程序将清除标记为删除的节点,但我感兴趣的是,数据库设计的更改或其他Oracle构造是否有助于解决此问题。除了在工作中学到的知识,我没有接受过甲骨文方面的培训,而创建数据库的人也没有考虑过这么多。我对数据库设计的改变是开放的,因为它还不是一个固定的设计。

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

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

ID, ParentID, TreeID 
1, [null], 1
ID, ParentID, TreeID
2, 1, 1
ID, ParentID, TreeID
3, 2, 1
级别2节点的外观如下所示:

ID, ParentID, TreeID 
1, [null], 1
ID, ParentID, TreeID
2, 1, 1
ID, ParentID, TreeID
3, 2, 1
级别3节点的外观如下所示:

ID, ParentID, TreeID 
1, [null], 1
ID, ParentID, TreeID
2, 1, 1
ID, ParentID, TreeID
3, 2, 1
等等


您可以使用(通过查询连接)来查询或遍历树。这个表将非常薄(不是很多列,这3个+一些修改的日期可能),所以更新这些关系应该比处理主表快得多,伸缩性更好

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

如果您的外键约束(在I_Parent_节点上)尚未可延迟,请删除它并使用关键字“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。

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

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


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

我忘记添加,为了提高性能,员工id和经理id都应该被索引(I_节点和I_父节点列);如果没有,子查询可能会成为一个瓶颈。您可以编辑自己的帖子,添加您忘记的内容。只需单击底部的编辑按钮,并确保更改是正确的。您的意思是“在自引用表上不允许级联删除”?对我来说似乎工作正常:
创建表test1(I\u节点号主键、I\u父节点号、约束test1\u fk外键(I\u父节点)在删除级联上引用test1(I\u节点)