P1:Parece que no hay nada sobre el tiempo de cálculo, solo un error en el algoritmo del optimizador que lo vuelve loco al calcular el mejor plan de ejecución.
P2:Hay una serie de errores conocidos y corregidos en Oracle 11.X.0.X relacionados con la optimización de consultas anidadas y la factorización de consultas. Pero es muy difícil encontrar un problema concreto.
P3:Hay dos indocumentados consejos:materialize
y inline
pero ninguno de ellos funciona para mí mientras probé tu ejemplo. Es posible que algunos cambios en la configuración del servidor o la actualización a 11.2.0.3 puedan aumentar el límite de with
anidados cláusulas:para mí (en 11.2.0.3 Win7/x86) su ejemplo funciona bien, pero aumentar el número de tablas anidadas a 30 bloquea una sesión.
La solución puede verse así:
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
)
Al menos funciona para mí en el nivel de anidamiento de 30 y produce un plan de ejecución totalmente diferente con WINDOW BUFFER
y VIEW
en lugar de LOAD TABLE AS SELECT
, SORT AGGREGATE
y TABLE ACCESS FULL
.
Actualizar
-
Acabo de instalar 11.2.0.4 (Win7/32bit) y pruébelo con la consulta inicial. Nada cambió en el comportamiento del optimizador.
-
No hay posibilidad de afectar directamente el comportamiento de una CBO, incluso con el uso de
inline
(sin documentar) oRULE
(en desuso) sugerencias. Puede haber algún Gurú que conozca alguna variante, pero es un alto secreto para mí (y para Google también :-). -
Es posible hacer cosas en una declaración de selección única en un tiempo razonable si una declaración de selección principal se separa en partes y se coloca en la función que devuelve un conjunto de filas (función que devuelve sys_refcursor o cursor de tipo fuerte), pero no es una opción si una consulta construido en tiempo de ejecución.
-
Es posible una solución con el uso de XML,
pero esta variante parece quitar una amígdala por el agujero del culo(perdón):
.
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
)
)
)
)))
Otra cosa sobre un código extraño anterior es que esta variante solo se aplica si with
los conjuntos de datos no tenían una gran cantidad de filas.