Q1:Sembra che non ci sia nulla sul tempo di calcolo, solo bug nell'algoritmo di ottimizzazione che lo rendono pazzo durante il calcolo di un piano di esecuzione migliore.
D2:Esistono numerosi bug noti e corretti in Oracle 11.X.0.X relativi all'ottimizzazione delle query nidificate e al fattore di query. Ma è molto difficile trovare un problema concreto.
Q3:Ci sono due non documentati suggerimenti:materialize
e inline
ma nessuno di loro funziona per me mentre ho provato il tuo esempio. È possibile che alcune modifiche alla configurazione del server o l'aggiornamento a 11.2.0.3 possano aumentare il limite di with
nidificato clausole:per me (su 11.2.0.3 Win7/x86) il tuo esempio funziona bene, ma aumentando il numero di tabelle nidificate a 30 si blocca una sessione.
La soluzione potrebbe essere simile a questa:
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
)
Almeno funziona per me a livello di annidamento 30 e produce un piano di esecuzione completamente diverso con WINDOW BUFFER
e VIEW
invece di LOAD TABLE AS SELECT
, SORT AGGREGATE
e TABLE ACCESS FULL
.
Aggiorna
-
Ho appena installato 11.2.0.4 (Win7/32bit) e testalo rispetto alla query iniziale. Nulla è cambiato nel comportamento dell'ottimizzatore.
-
Non ci sono possibilità di influenzare direttamente un comportamento CBO, anche con l'uso di
inline
(non documentato) oRULE
(obsoleto) suggerimenti. Forse qualche Guru conosce una qualche variante, ma è un Top Secret per me (e anche per Google :-) . -
È possibile eseguire operazioni in un'istruzione one select in un tempo ragionevole se un'istruzione select principale è separata in parti e inserita nella funzione che restituisce un insieme di righe (funzione che restituisce sys_refcursor o un cursore digitato forte), ma non è una scelta se una query costruito in fase di esecuzione.
-
È possibile una soluzione alternativa con l'utilizzo di XML,
ma questa variante sembra rimuovere una tonsilla attraverso il buco del culo(scusate):
.
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
)
)
)
)))
Un'altra cosa su uno strano codice sopra è che questa variante è applicabile solo se with
i set di dati non avevano un numero elevato di righe.