Q1:Изглежда, че няма нищо за времето за изчисление, просто грешка в алгоритъма на оптимизатора, която го вбесява, докато изчислява най-добрия план за изпълнение.
Q2:Има редица известни и коригирани грешки в Oracle 11.X.0.X, свързани с оптимизиране на вложени заявки и факторизиране на заявки. Но е много трудно да се намери конкретен проблем.
Q3:Има две недокументирани подсказки:materialize
и inline
но никой от тях не работи за мен, докато пробвах вашия пример. Възможно е някои промени в конфигурацията на сървъра или надстройката до 11.2.0.3 да увеличат ограничението на вложените with
клаузи:за мен (на 11.2.0.3 Win7/x86) вашият пример работи добре, но увеличаването на броя на вложените таблици до 30 спира сесията.
Заобиколното решение може да изглежда така:
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
)
Поне за мен работи на ниво на влагане 30 и създава напълно различен план за изпълнение с WINDOW BUFFER
и VIEW
вместо LOAD TABLE AS SELECT
, SORT AGGREGATE
и TABLE ACCESS FULL
.
Актуализация
-
Току-що инсталирах 11.2.0.4 (Win7/32bit) и го тествам спрямо първоначалната заявка. Нищо не се промени в поведението на оптимизатора.
-
Няма възможност за пряко въздействие върху поведението на CBO, дори при използване на
inline
(недокументирано) илиRULE
(отхвърлени) съвети. Може някой гуру да знае някакъв вариант, но това е строго секретно за мен (и за Google също :-) . -
Правенето на неща в един оператор за избор в разумно време е възможно, ако основен оператор за избор е разделен на части и поставен във функцията, която връща набор от редове (функция, връщаща sys_refcursor или строго въведен курсор), но не е избор, ако заявка конструиран по време на изпълнение.
-
Възможно е заобиколно решение с използване на XML,
но този вариант изглежда като премахване на сливица през дупката на задника(съжалявам):
.
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
)
)
)
)))
Друго нещо относно странния код по-горе е, че този вариант е приложим само ако with
наборите от данни не са имали голям брой редове.