我有一个代表树的历史传递闭包表。
create table TRANSITIVE_CLOSURE
(
CHILD_NODE_ID number not null enable,
ANCESTOR_NODE_ID number not null enable,
DISTANCE number not null enable,
FROM_DATE date not null enable,
TO_DATE date not null enable,
constraint TRANSITIVE_CLOSURE_PK unique (CHILD_NODE_ID, ANCESTOR_NODE_ID, DISTANCE, FROM_DATE, TO_DATE)
);
以下是一些示例数据:
CHILD_NODE_ID | ANCESTOR_NODE_ID | DISTANCE
--------------------------------------------
1 | 1 | 0
2 | 1 | 1
2 | 2 | 0
3 | 1 | 2
3 | 2 | 1
3 | 3 | 0
不幸的是,我当前查找根节点的查询会导致全表扫描:
select *
from transitive_closure tc
where
distance = 0
and not exists (
select null
from transitive_closure tci
where tc.child_node_id = tci.child_node_id
and tci.distance <> 0
);
从表面上看,它看起来并不太昂贵,但是当我接近 100 万行时,这个特定的查询开始变得令人讨厌......尤其是当它是一个 View 的一部分时,它会捕获邻接树以获得遗留支持。
有没有更好的方法来找到传递闭包的根节点?我想重写我们所有的旧遗留代码,但我不能......所以我需要以某种方式构建邻接列表。获取除根节点之外的所有内容都很容易,那么有没有更好的方法?我是否以错误的方式思考这个问题?
对具有 800k 行的表的查询计划。
OPERATION OBJECT_NAME OPTIONS COST
SELECT STATEMENT 2301
HASH JOIN RIGHT ANTI 2301
Access Predicates
TC.CHILD_NODE_ID=TCI.CHILD_NODE_ID
TABLE ACCESS TRANSITIVE_CLOSURE FULL 961
Filter Predicates
TCI.DISTANCE = 1
TABLE ACCESS TRANSITIVE_CLOSURE FULL 962
Filter Predicates
DISTANCE=0
最佳答案
执行查询需要多长时间,您希望它需要多长时间? (您通常不想使用成本进行调整。很少有人知道解释计划成本的真正含义。)
在我的慢速桌面上,查询 800K 行只需要 1.5 秒。然后在数据进入内存后 0.5 秒。你是不是变得更糟了,
还是会非常频繁地运行此查询?
我不知道你的数据是什么样的,但我猜全表扫描对于这个查询来说总是最好的。假设您的分层数据
相对较浅,即0和1的距离很多,但100的距离很少,最重要的列不会很明显。这表示
距离的任何索引条目都将指向大量 block 。使用多 block 读取一次读取整个表会便宜得多
而不是一次一个 block 地读取大量内容。
另外,你说的历史是什么意思?您可以将此查询的结果存储在物化 View 中吗?
另一个可能的想法是使用分析函数。这用排序替换了第二个表扫描。这种方法通常更快,但对我来说
查询实际上需要更长的时间,5.5 秒而不是 1.5 秒。但也许它在您的环境中会做得更好。
select * from
(
select
max(case when distance <> 0 then 1 else 0 end)
over (partition by child_node_id) has_non_zero_distance
,transitive_closure.*
from transitive_closure
)
where distance = 0
and has_non_zero_distance = 0;
关于sql - 如何加快寻找传递闭包根节点的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5264637/