V1:Het lijkt erop dat er niets is over de berekeningstijd, alleen een bug in het optimalisatiealgoritme waardoor het gek wordt tijdens het berekenen van een plan voor de beste uitvoering.
V2:Er zijn een aantal bekende en opgeloste bugs in Oracle 11.X.0.X met betrekking tot optimalisatie van geneste query's en factoring van query's. Maar het is erg moeilijk om een concreet probleem te vinden.
Q3:Er zijn twee ongedocumenteerde hints:materialize
en inline
maar geen van hen werkt voor mij terwijl ik jouw voorbeeld probeerde. Het is mogelijk dat sommige wijzigingen in de serverconfiguratie of het upgraden naar 11.2.0.3 de limiet van geneste with
verhogen clausules:voor mij (op 11.2.0.3 Win7/x86) werkt uw voorbeeld prima, maar een toenemend aantal geneste tabellen naar 30 loopt vast in een sessie.
Tijdelijke oplossing kan er als volgt uitzien:
select k from (
select k, avg(k) over (partition by null) k_avg from ( --t16
select k, avg(k) over (partition by null) k_avg from ( --t15
select k, avg(k) over (partition by null) k_avg from ( --t14
select k, avg(k) over (partition by null) k_avg from ( --t13
select k, avg(k) over (partition by null) k_avg from ( --t12
select k, avg(k) over (partition by null) k_avg from ( --t11
select k, avg(k) over (partition by null) k_avg from ( --t10
select k, avg(k) over (partition by null) k_avg from ( --t9
select k, avg(k) over (partition by null) k_avg from ( --t8
select k, avg(k) over (partition by null) k_avg from ( --t7
select k, avg(k) over (partition by null) k_avg from ( --t6
select k, avg(k) over (partition by null) k_avg from ( --t5
select k, avg(k) over (partition by null) k_avg from ( --t4
select k, avg(k) over (partition by null) k_avg from ( --t3
select k, avg(k) over (partition by null) k_avg from ( --t2
select k, avg(k) over (partition by null) k_avg from ( -- t1
select k, avg(k) over (partition by null) k_avg from (select 0 as k from dual) t0
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
) where k >= k_avg
)
Het werkt tenminste voor mij op nesting-niveau van 30 en produceert een totaal ander uitvoeringsplan met WINDOW BUFFER
en VIEW
in plaats van LOAD TABLE AS SELECT
, SORT AGGREGATE
en TABLE ACCESS FULL
.
Bijwerken
-
Heb zojuist 11.2.0.4 (Win7/32bit) geïnstalleerd en test het tegen de eerste zoekopdracht. Er is niets veranderd in het gedrag van de optimalisatie.
-
Er is geen mogelijkheid om het gedrag van een CBO direct te beïnvloeden, zelfs niet bij gebruik van
inline
(ongedocumenteerd) ofRULE
(verouderde) tips. Misschien kent een goeroe een variant, maar het is een Top Secret voor mij (en Google ook :-) . -
Het is mogelijk om binnen een redelijke tijd dingen te doen in een één-select-instructie als een hoofd-select-instructie wordt opgesplitst in delen en in de functie wordt geplaatst die een reeks rijen retourneert (functie die sys_refcursor of sterk getypte cursor retourneert), maar het is geen keuze als een query gebouwd tijdens runtime.
-
Tijdelijke oplossing met gebruik van XML is mogelijk,
maar deze variant lijkt op het verwijderen van een amandel door het kontgat(sorry):
.
select
extractvalue(column_value,'/t/somevalue') abc
from
table(xmlsequence((
select t2 from (
select
t0,
t1,
(
select xmlagg(
xmlelement("t",
xmlelement("k1",extractvalue(t1t.column_value,'/t/k1')),
xmlelement("somevalue", systimestamp))
)
from
table(xmlsequence(t0)) t0t,
table(xmlsequence(t1)) t1t
where
extractvalue(t1t.column_value,'/t/k1') >= (
select avg(extractvalue(t1t.column_value, '/t/k1')) from table(xmlsequence(t1))
)
and
extractvalue(t0t.column_value,'/t/k2') > 6
) t2
from (
select
t0,
(
select xmlagg(
xmlelement("t",
xmlelement("k1",extractvalue(column_value,'/t/k1')),
xmlelement("somevalue", sysdate))
)
from table(xmlsequence(t0))
where
extractvalue(column_value,'/t/k1') >= (
select avg(extractvalue(column_value, '/t/k1')) from table(xmlsequence(t0))
)
) t1
from (
select
xmlagg(xmlelement("t", xmlelement("k1", level), xmlelement("k2", level + 3))) t0
from dual connect by level < 5
)
)
)
)))
Een ander ding over een vreemde code hierboven is dat deze variant alleen van toepassing is als with
datasets hadden niet een groot aantal rijen.