sql >> Databáze >  >> RDS >> Oracle

Pomalý výkon pro hluboce vnořený faktoring poddotazů (CTE)

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

  1. 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.

  2. Neexistuje žádná možnost přímo ovlivnit chování CBO, a to ani při použití inline (nedokumentováno) nebo RULE (zastaralé) rady. Možná nějaký guru zná nějakou variantu, ale pro mě (a pro Google také) je to přísně tajné.

  3. 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.

  4. Ř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ů.



  1. Jak se připojit k databázi mysql v phonegap

  2. Vytvoření CRUD pomocí PHP + Bootstrap Modal + Mysql + JS

  3. Několik nápadů o nízkoúrovňovém sdružování zdrojů v PostgreSQL

  4. Odstraňte dvojité uvozovky z pole json selektivním způsobem v PostgreSQL