Otázka 1:Zdá se, že zde není nic o době výpočtu, pouze chyba v optimalizačním algoritmu, kvůli které je při výpočtu nejlepšího plánu provedení šílené.
Q2:V Oracle 11.X.0.X je řada známých a opravených chyb souvisejících s optimalizací vnořených dotazů a faktoringu dotazů. Ale je velmi těžké najít konkrétní problém.
Otázka 3:Existují dva nedokumentované rady:materialize
a inline
ale žádný z nich mi nefunguje, když jsem zkoušel váš příklad. Je možné, že některé změny v konfiguraci serveru nebo upgrade na 11.2.0.3 mohou zvýšit limit vnořených with
klauzule:pro mě (na 11.2.0.3 Win7/x86) váš příklad funguje dobře, ale zvýšení počtu vnořených tabulek na 30 zastaví relaci.
Řešení může vypadat takto:
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
)
Alespoň pro mě to funguje na úrovni vnoření 30 a vytváří úplně jiný plán provádění s WINDOW BUFFER
a VIEW
místo LOAD TABLE AS SELECT
, SORT AGGREGATE
a TABLE ACCESS FULL
.
Aktualizovat
-
Právě jsem nainstaloval 11.2.0.4 (Win7/32bit) a otestoval jej proti počátečnímu dotazu. V chování optimalizátoru se nic nezměnilo.
-
Neexistuje žádná možnost přímo ovlivnit chování CBO, a to ani při použití
inline
(nedokumentováno) neboRULE
(zastaralé) rady. Možná nějaký guru zná nějakou variantu, ale pro mě (a pro Google také) je to přísně tajné. -
Dělat věci v jednom příkazu select v přiměřeném čase je možné, pokud je hlavní příkaz select rozdělen na části a umístěn do funkce, která vrací sadu řádků (funkce vracející sys_refcursor nebo silný typový kurzor), ale není to volba, pokud dotaz vytvořené za běhu.
-
Řešení s použitím XML je možné,
ale tato varianta vypadá jako odstranění krční mandle dírou v zadku(omlouvám se):
.
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
)
)
)
)))
Další věc na podivném kódu výše je, že tato varianta je použitelná pouze v případě, že with
datové sady neměly velký počet řádků.