Oracle
 sql >> база данни >  >> RDS >> Oracle

Бавна производителност за факторинг на дълбоко вложени подзаявки (CTE)

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 .

Актуализация

  1. Току-що инсталирах 11.2.0.4 (Win7/32bit) и го тествам спрямо първоначалната заявка. Нищо не се промени в поведението на оптимизатора.

  2. Няма възможност за пряко въздействие върху поведението на CBO, дори при използване на inline (недокументирано) или RULE (отхвърлени) съвети. Може някой гуру да знае някакъв вариант, но това е строго секретно за мен (и за Google също :-) .

  3. Правенето на неща в един оператор за избор в разумно време е възможно, ако основен оператор за избор е разделен на части и поставен във функцията, която връща набор от редове (функция, връщаща sys_refcursor или строго въведен курсор), но не е избор, ако заявка конструиран по време на изпълнение.

  4. Възможно е заобиколно решение с използване на 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 наборите от данни не са имали голям брой редове.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 4 начина за вмъкване на няколко реда в Oracle

  2. Как да отпечатам резултата в различен ред с помощта на SQL заявка?

  3. Защо в Oracle SQL изтритите (некоммитирани) редове не се виждат в текущата сесия, но се виждат в други сесии?

  4. Как мога да разреша грешка ORA-01427 (подзаявката с един ред връща повече от един ред)?

  5. Извличане на големи clob данни с помощта на sqlplus