sql >> Database >  >> RDS >> Oracle

Trage prestaties voor diep geneste subquery factoring (CTE)

V1:Het lijkt erop dat er niets is over de berekeningstijd, alleen een bug in het optimalisatiealgoritme waardoor het gek wordt tijdens het berekenen van een plan voor de beste uitvoering.

V2:Er zijn een aantal bekende en opgeloste bugs in Oracle 11.X.0.X met betrekking tot optimalisatie van geneste query's en factoring van query's. Maar het is erg moeilijk om een ​​concreet probleem te vinden.

Q3:Er zijn twee ongedocumenteerde hints:materialize en inline maar geen van hen werkt voor mij terwijl ik jouw voorbeeld probeerde. Het is mogelijk dat sommige wijzigingen in de serverconfiguratie of het upgraden naar 11.2.0.3 de limiet van geneste with verhogen clausules:voor mij (op 11.2.0.3 Win7/x86) werkt uw voorbeeld prima, maar een toenemend aantal geneste tabellen naar 30 loopt vast in een sessie.

Tijdelijke oplossing kan er als volgt uitzien:

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
)

Het werkt tenminste voor mij op nesting-niveau van 30 en produceert een totaal ander uitvoeringsplan met WINDOW BUFFER en VIEW in plaats van LOAD TABLE AS SELECT , SORT AGGREGATE en TABLE ACCESS FULL .

Bijwerken

  1. Heb zojuist 11.2.0.4 (Win7/32bit) geïnstalleerd en test het tegen de eerste zoekopdracht. Er is niets veranderd in het gedrag van de optimalisatie.

  2. Er is geen mogelijkheid om het gedrag van een CBO direct te beïnvloeden, zelfs niet bij gebruik van inline (ongedocumenteerd) of RULE (verouderde) tips. Misschien kent een goeroe een variant, maar het is een Top Secret voor mij (en Google ook :-) .

  3. Het is mogelijk om binnen een redelijke tijd dingen te doen in een één-select-instructie als een hoofd-select-instructie wordt opgesplitst in delen en in de functie wordt geplaatst die een reeks rijen retourneert (functie die sys_refcursor of sterk getypte cursor retourneert), maar het is geen keuze als een query gebouwd tijdens runtime.

  4. Tijdelijke oplossing met gebruik van XML is mogelijk, maar deze variant lijkt op het verwijderen van een amandel door het kontgat (sorry):

.

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
        )
      )
    )
  )))

Een ander ding over een vreemde code hierboven is dat deze variant alleen van toepassing is als with datasets hadden niet een groot aantal rijen.



  1. kunnen we een standaardbeperking in Oracle noemen?

  2. Verkrijg ConnectionString van app.config in c#

  3. RSS-generator met caching-functie

  4. Moet ik voorbereide instructies voor MySQL gebruiken in PHP PERFORMANCE-WISE?