Ich habe eine historische Tabelle mit transitivem Abschluss, die einen Baum darstellt.
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)
);
Hier sind einige Beispieldaten:
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
Leider verursacht meine aktuelle Abfrage zum Auffinden des Stammknotens eine vollständige Tabellendurchsuchung:
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
);
Oberflächlich betrachtet sieht es nicht allzu teuer aus, aber wenn ich mich 1 Million Zeilen nähere, fängt diese spezielle Abfrage an, unangenehm zu werden... vor allem, wenn sie Teil einer Ansicht ist, die den Adjazenzbaum für Legacy-Unterstützung abruft.
Gibt es eine bessere Möglichkeit, den Wurzelknoten eines transitiven Abschlusses zu finden? Ich würde gerne unseren gesamten alten Code neu schreiben, aber das kann ich nicht... also muss ich die Adjazenzliste irgendwie erstellen. Alles außer dem Wurzelknoten zu erhalten ist einfach, gibt es also einen besseren Weg? Denke ich über dieses Problem auf die falsche Weise?
Abfrageplan für eine Tabelle mit 800k Zeilen.
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