1

我有一个包含分层数据的表。目前在这个层次中有〜8个层次。创建分层定义的数据集的展平表/视图

我真的很喜欢的方式,数据的结构,但性能是令人沮丧的,当我需要知道,如果在8级的纪录是在级别1

记录的一个孩子,我有PL/SQL存储函数为我做这些查询,每个都有一个select * from tbl start with ... connect by...声明。当我查询一些记录时,这很好,但我现在处于一种情况,我需要一次查询〜10k条记录,并且每个记录都运行此函数。这需要2-3分钟,我需要它在几秒钟内运行。

根据我对当前数据的了解,我可以摆脱查找功能,只是做childrecord.key || '%' LIKE parentrecord.key,但这是一个非常肮脏的黑客攻击,并不总是工作。

所以现在我想这对于这个分层定义的表我需要有一个单独的父子表,它将包含每一个关系...对于层次从1-8级将会有8!记录,将1与2,1与3,...,1与8和2与3,2与4,...,2与8相关联。等等。

我的想法是,我需要一个插入触发器,它将基本上运行connect by查询,对于层次结构中的每个匹配项,它都会在查找表中插入一条记录。而为了处理旧数据,我只需将级联删除的外键设置到主表。

有没有比这更好的选择?我是否错过了另一种可以更快地确定这些遥远的祖先/后代关系的方式?

编辑:这似乎正是我在想:http://evolt.org/working_with_hierarchical_data_in_sql_using_ancestor_tables

+0

您是否主要对回答“谁是我的最终父母?”这个问题感兴趣?或者“谁是我的第一位父亲,并定义了一些属性?”如果是这样,物化视图可能比触发器更容易和更安全。 – 2010-08-02 23:47:12

+0

@Adam Musch:我很想知道任何两个记录是否相互关联。你指的是什么样的安全问题?未能锁定相应的记录并获取损坏的数据? – 2010-08-03 04:24:19

+0

主要是数据损坏,是的。通过表维护传递闭包v物化视图意味着可以独立更新 - 触发器可以被禁用,映射表可以有针对它们写入的SQL。我写了物化视图来看“上游”来回答我在我之前的评论中提到的问题,但不回答“谁是B的祖先的全部”或“是B的祖先?”的通用形式。 – 2010-08-03 12:45:19

回答

2

所以,你想要的是物化的传递闭。也就是说,考虑到该应用程序表...

ID | PARENT_ID 
------+---------- 
    1 | 
    2 |   1 
    3 |   2 
    4 |   2 
    5 |   4 

...图形表是这样的:

PARENT_ID | CHILD_ID 
-----------+---------- 
     1 |  2 
     1 |  3 
     1 |  4 
     1 |  5 
     2 |  3 
     2 |  4 
     2 |  5 
     4 |  5 

很可能维持这样Oracle中的表,虽然你会需要为它推出自己的框架。问题是这是否值得开销。如果源表非常不稳定,那么保持图表数据更新可能会花费更多的周期,这比您在查询中保存的周期还要多。只有你知道你的数据的个人资料。

我不认为你可以用CONNECT BY查询和级联外键维护这样一个图表。太多的间接活动,太难以正确对待。此外,物化视图已不存在,因为我们无法编写SQL查询,该查询在删除ID=4的源记录时将删除1->5记录。

所以我建议你阅读Dong,Libkin,Su和Wong的文章Maintaining Transitive Closure of Graphs in SQL。这包含了许多理论和一些粗糙的(Oracle)SQL,但它会为您建立维护图表所需的PL/SQL奠定基础。


“你能在有关部分展开 太困难 CONNECT BY /级联FKS维护?如果我控制 访问表和所有 插入/更新/删除发生通过 存储过程,有哪些 场景在那里会出现这种情况, 会崩溃?“

考虑记录1->5这是1->2->4->5的短路。现在如果像我之前说过的那样删除ID=4的源记录,会发生什么情况?级联外键可以删除2->44->5的条目。但是这在图表中留下了1->5(实际上2->5),尽管它们不再代表图中的有效边缘。

什么可能工作(我想,我没有这样做)将是在源表中使用一个额外的合成密钥,就像这样。现在

ID | PARENT_ID | NEW_KEY 
------+-----------+--------- 
    1 |   | AAA 
    2 |   1 | BBB 
    3 |   2 | CCC 
    4 |   2 | DDD 
    5 |   4 | EEE 

图形表是这样的:

PARENT_ID | CHILD_ID | NEW_KEY 
-----------+----------+--------- 
     1 |  2 | BBB 
     1 |  3 | CCC 
     1 |  4 | DDD 
     1 |  5 | DDD 
     2 |  3 | CCC 
     2 |  4 | DDD 
     2 |  5 | DDD 
     4 |  5 | DDD 

使图形表有一个外键引用中产生的,而不是链接到ID源表的关系。然后删除ID=4的记录将级联删除图表中的所有记录,其中NEW_KEY=DDD

如果任何给定的ID只能有零个或一个父ID,这将工作。但它不会工作,如果它是允许这种情况发生:

ID | PARENT_ID 
------+---------- 
    5 |   2 
    5 |   4 

换句话说边缘1->5既代表1->2->4->51->2->5。那么,可能会发挥什么取决于数据的复杂性。

+0

我有两个表我想申请这个 - 一个是易失性的,另一个是在一个单线程过程中只在非工作时间更新一次。我的希望是首先在较不稳定的表上实现它,然后在我解决所有问题时将该框架移植到另一个表。 我还没有吸收您链接到的纸张的所有内容,但它确实看起来正是我要找的。 – 2010-08-03 14:33:57

+0

我并不质疑你的判断,但是你能否扩展关于使用CONNECT BY /级联FK难以维护的部分?如果我控制对表的访问,并且通过存储过程发生所有插入/更新/删除操作,那么会出现哪种情况会导致崩溃?即使其他人有直接插入/更新/删除访问权限,如果逻辑是在触发器/级联FKs中实现的,那么我会遇到什么样的问题? – 2010-08-03 14:35:07