sql >> データベース >  >> RDS >> Oracle

深くネストされたサブクエリファクタリング(CTE)のパフォーマンスが遅い

    Q1:計算時間については何もないようです。最適化アルゴリズムのバグが原因で、最適な実行プランを計算しているときに問題が発生します。

    Q2:Oracle 11.X.0.Xには、ネストされたクエリの最適化とクエリの因数分解に関連する既知の修正済みのバグがいくつかあります。しかし、具体的な問題を見つけるのは非常に困難です。

    Q3:文書化されていないが2つあります ヒント: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 / 32ビット)をインストールし、最初のクエリに対してテストします。オプティマイザの動作に変更はありません。

    2. inlineを使用しても、CBOの動作に直接影響を与える可能性はありません。 (文書化されていない)またはRULE (非推奨)ヒント。いくつかの教祖がいくつかの変種を知っているかもしれませんが、それは私にとって(そしてGoogleも:-)トップシークレットです。

    3. メインのselectステートメントがパーツに分割され、行のセットを返す関数(sys_refcursorまたは強い型のカーソルを返す関数)に配置されている場合、1つのselectステートメントで適切な時間内に処理を実行できますが、クエリの場合は選択できません。実行時に構築されます。

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

    上記の奇妙なコードに関するもう1つの点は、このバリアントはwithの場合にのみ適用できるということです。 データセットには大きな行数はありませんでした。



    1. PL/SQLで文字列内の個別の文字の数と名前を見つける方法

    2. MySQLでのmemcacheはどのように機能しますか?

    3. SQL ServerReportingServicesの調整

    4. 別のバージョンのWebサイト