P1:Wydaje się, że nie ma nic o czasie obliczania, tylko błąd w algorytmie optymalizacyjnym, który sprawia, że jest szalony podczas obliczania najlepszego planu wykonania.
P2:Istnieje wiele znanych i naprawionych błędów w Oracle 11.X.0.X związanych z optymalizacją zapytań zagnieżdżonych i faktoringiem zapytań. Ale bardzo trudno jest znaleźć konkretny problem.
P3:Istnieją dwa nieudokumentowane podpowiedzi:materialize
i inline
ale żaden z nich nie działa dla mnie, gdy próbowałem twojego przykładu. Możliwe, że niektóre zmiany w konfiguracji serwera lub aktualizacja do wersji 11.2.0.3 mogą zwiększyć limit zagnieżdżonych with
klauzule:dla mnie (na 11.2.0.3 Win7/x86) twój przykład działa dobrze, ale zwiększenie liczby zagnieżdżonych tabel do 30 zawiesza sesję.
Obejście może wyglądać tak:
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
)
Przynajmniej u mnie działa na poziomie zagnieżdżenia 30 i tworzy zupełnie inny plan wykonania z WINDOW BUFFER
i VIEW
zamiast LOAD TABLE AS SELECT
, SORT AGGREGATE
i TABLE ACCESS FULL
.
Aktualizacja
-
Właśnie zainstalowałem 11.2.0.4 (Win7/32bit) i przetestowałem go z początkowym zapytaniem. Nic się nie zmieniło w zachowaniu optymalizatora.
-
Nie ma możliwości bezpośredniego wpływu na zachowanie CBO, nawet przy użyciu
inline
(nieudokumentowane) lubRULE
(przestarzałe) podpowiedzi. Może jakiś guru zna jakiś wariant, ale dla mnie (i Google też :-) jest to ściśle tajne . -
Wykonywanie czynności za pomocą jednej instrukcji select w rozsądnym czasie jest możliwe, jeśli główna instrukcja select podzielona na części i umieszczona w funkcji, która zwraca zestaw wierszy (funkcja zwracająca sys_refcursor lub kursor o silnym typie), ale nie jest to wybór, jeśli zapytanie zbudowany w czasie wykonywania.
-
Obejście z użyciem XML jest możliwe,
ale ten wariant wygląda jak usunięcie migdałka przez dziurę w dupie(przepraszam):
.
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
)
)
)
)))
Inną rzeczą związaną z dziwnym kodem powyżej jest to, że ten wariant ma zastosowanie tylko wtedy, gdy with
zestawy danych nie miały dużej liczby wierszy.