2011-07-20 86 views
2

パフォーマンスが低下しているクエリがあります。クエリの1つの側面は、テーブル値関数のクロス結合を使用することです。正直なところ、スカラー関数呼び出しの使用を避ける関数にCROSS APPLYを使用するTSQLの動作を模倣していました。 Oracleではこれが悪い行為ですか?選択とテーブル値関数のOracleスカラー関数の結合

主な問題は、Oracle Tuning Advisorが問合せを解析しないため、索引の最適化をまだ調査できないことです。通常、私はこの多くのコードを投稿しませんが、問題を引き起こしている可能性のあるテーブルの最適化以上のクエリだと思われます。

実際には、統計テーブルは4,000,000を超えるレコードを持つ唯一のテーブルです。誰かが露骨な悪いOracleの行動の除去をお勧めできますか?または、すべてのインデックスチューニングアドバイザを得るための良いツールに見える場合は? Oracle Enterprise Managerは、この問合せを解析して推奨事項を提供しません。

追加パフォーマンス情報は、トレースからキャプチャし、TKPROFを通じて をフォーマットし

解析:カウント(1)| CPU(0.04)|経過(0.04)|ディスク(0)|クエリ(852)|現在の(0)|行(0)

実行:Count(1)| CPU(0.00)|経過(0.00)|ディスク(0)|クエリ(0)|現在の(0)|行(0)

フェッチ:カウント(1)| CPU(9.64)|経過(14.50)|ディスク(34578)|クエリ(35610)|現在の(4)|行構文解析時にライブラリ・キャッシュ(4)

ミス:1 オプティマイザモード:ALL_ROWS ユーザIDを解析:1165

行の行ソース操作


4 HASH JOIN OUTER (cr=38069 pr=34578 pw=0 time=19208475 us) 
    2 COLLECTION ITERATOR PICKLER FETCH REPORT_INTERVAL_SEQUENCE_UDF (cr=97 pr=0 >                 pw=0 time=13766 us) 
    4 VIEW (cr=37972 pr=34578 pw=0 time=19194353 us) 
    4 HASH GROUP BY (cr=37972 pr=34578 pw=0 time=19194329 us) 

60650 FILTER(CR = 37972 PR = 34578 PW = 0時間= 19673947米国)を
60650ネストされたループ(CR = 37972 PR = 34578 PW = 0時間= 19431329米国)を
60650 HASH JOIN(CR = 37 941 PR = 34578 PW = 0時間= 5294908 US) 4 COLLECTION ITERATOR PicklerさんFETCH REPORT_MACHINEINFO_GETT_UDF(CR = 2331 PR = 0 PW = 0時間= 212033米国)
60650 TABLE ACCESS FULL ELS_STATISTIC_ENTRY(CR = 35610 PR = 34578 PW = 0 時間= 4416705たちを)
60650 COLLECTION ITERATOR PicklerさんFETCH REPORT_INTERVAL_GETT_UDF(CR = 31 PR = 0> PW = 0時間= 13372794私たち)

SELECT 
     TimeInterval, 
     stats.During, 
     stats.Name, 
     stats.cnt 
    FROM 
     TABLE (GET_INTERVAL_SEQUENCE_UDF(
             TO_TIMESTAMP ('07/15/2011','mm/dd/yyyy') 
             ,TO_TIMESTAMP ('07/20/2011','mm/dd/yyyy') 
             ,2)) dtRange 
    LEFT JOIN 
    (
     SELECT 
       i.During 
       , mi.Name 
       , SUM (CAST (VALUE_NUMERIC AS INT)) cnt 

     FROM 
       statistics se 
     JOIN TABLE (Get_Context_Info_udf()) mi 
       ON (se.Context_ID = mi.Context_ID) 
     CROSS JOIN TABLE (Interval_GetT (se.EntryDate, 2)) i 
     WHERE 
       StatisticTypeID = HEXTORAW ('6CF933B091AE46FEA7F56BE96308190F') 
       AND EntryDate < TO_TIMESTAMP ('07/20/2011','mm/dd/yyyy') 
       AND EntryDate > TO_TIMESTAMP ('07/15/2011', 'mm/dd/yyyy') 
     GROUP BY 
      i.During 
      , mi.Name 
    ) stats ON dtRange.TimeInterval = stats.TimeInterval 


The following are for reference in the aforementioned query. 


CREATE OR REPLACE FUNCTION Interval_GetT(datestamp IN timestamp, timeInterval IN int) 
RETURN TReportIntervalList AS vResult TReportIntervalList; 
BEGIN 
    SELECT TReportInterval(
          CASE timeInterval 
          WHEN 1 THEN TO_CHAR(datestamp, 'YYYY-MM-DD HH24') 
          WHEN 2 THEN TO_CHAR(datestamp, 'YYYY-MM-DD') 
          WHEN 3 THEN TO_CHAR(datestamp, 'YYYY-WW') 
          END 
          ) 
    BULK COLLECT INTO vResult          
    FROM Dual WHERE ROWNUM = 1; 

    RETURN vResult; 
END; 



CREATE OR REPLACE FUNCTION GET_INTERVAL_SEQUENCE_UDF(
     startTime IN timestamp, 
     endTime IN timestamp, 
     inputInterval IN int) 
     RETURN t_interval_list_table AS intervalList t_interval_list_table := t_interval_list_table(); 
    BEGIN 

    SELECT 
     CASE inputInterval 
     WHEN 1 THEN (t_interval(REPORT_Interval_Get_udf((startTime + ((ROWNUM-1) * 1/24)), inputInterval))) --Hour 
     WHEN 2 THEN (t_interval(REPORT_Interval_Get_udf((startTime + (ROWNUM-1)), inputInterval))) --Day 
     WHEN 3 THEN (t_interval(REPORT_Interval_Get_udf((startTime + ((ROWNUM-1)*7)), inputInterval))) --Week 
      END 
      BULK COLLECT INTO intervalList 
      FROM dual CONNECT BY LEVEL <= (CASE inputInterval 
              WHEN 1 THEN CAST(CEIL(((TRUNC(endTime, 'HH') - TRUNC(startTime, 'HH')) * 24)) AS INT) 
              WHEN 2 THEN CAST(TRUNC(endTime, 'DD') - TRUNC(startTime, 'DD') AS INT) 
              WHEN 3 THEN CAST(CEIL(((TRUNC(endTime, 'DD') - TRUNC(startTime, 'DD')))/7) AS INT) 
             END); 
     RETURN intervalList; 

    END GET_INTERVAL_SEQUENCE_UDF; 


CREATE OR REPLACE FUNCTION  Get_Context_Info_udf 
    RETURN TTRFRMENGMACHINEINFOLIST AS vResult TTRFRMENGMACHINEINFOLIST; 
    BEGIN  
     SELECT TTrfrmEngMachineInfo(ch.Context_ID, mac.Name) 
     BULK COLLECT INTO vResult 
     FROM 
      a ch 
     INNER JOIN 
      b cxm ON ch.CONTX_MACHINE_ID = cxm.CONTX_MACHINE_ID 
     INNER JOIN 
      c mac ON cxm.MACHINE_ID = mac.MACHINE_ID 
     INNER JOIN 
      d ic ON mac.MACHINE_ID = ic.MACHINE_ID 
     WHERE 
      ic.ONFIGURABLE_ENTITY_ID = HEXTORAW(Format_Guid_udf('11111111-FAE9-47A1-91A9-60A53E9660FE')) 
      AND mac.IS_DELETED = 'N' 
      AND ic.IS_DELETED = 'N'; 

     RETURN vResult; 
    END; 
+4

次回は、人があなたの質問を解析するのを助けるために、段落と適切な句読点を使用してください。私たちの目がテキストをより速く索引付けするのに役立ちます。投稿したコードブロック全体を選択し、エディタの '{}'ボタンを押すと、かなり美しいものになります。 – Mat

+0

tkprofにはあなたのコレクションや機能の他の名前がここにあなたの投稿の残りの部分よりも言及されています。私はあなたがこの出力を生成するためにどのツールを使用したかわかりませんが、今のように、それは読みにくいです。 tkprofから直接コピー&ペーストを使用してください。また、tkprofファイル内の他のクエリは非常に関連しているようです。 tkprofのソートパラメータを使用すると、ファイルの先頭に取得することができます。 –

答えて

1

時間が費やされていると実行計画Oracleはthis OTN thread

よろしく、
ロブでアドバイスに従うことによって選ぶどこで調べることができます。

1

それはすべて私には外国人に見える:)

まず、SELECT FROM DUALは珍しいPL/SQLで使用します。

CREATE OR REPLACE FUNCTION Interval_GetT(datestamp IN timestamp, timeInterval IN int) 
RETURN TReportIntervalList AS vResult TReportIntervalList; 
BEGIN 
    SELECT TReportInterval(
       CASE timeInterval 
        WHEN 1 THEN TO_CHAR(datestamp, 'YYYY-MM-DD HH24') 
        WHEN 2 THEN TO_CHAR(datestamp, 'YYYY-MM-DD') 
        WHEN 3 THEN TO_CHAR(datestamp, 'YYYY-WW') 
       END) 
    BULK COLLECT INTO vResult          
    FROM Dual WHERE ROWNUM = 1; 

    RETURN vResult; 
END; 

は単純

CREATE OR REPLACE FUNCTION Interval_GetT(datestamp IN timestamp, timeInterval IN int) 
RETURN TReportIntervalList; 
BEGIN 
    IF timeInterval = 1 THEN 
     RETURN TReportInterval(TO_CHAR(datestamp, 'YYYY-MM-DD HH24')); 
    ELSIF timeInterval = 2 THEN 
     RETURN TReportInterval(TO_CHAR(datestamp, 'YYYY-MM-DD')); 
    ELSIF timeInterval = 3 THEN 
     RETURN TReportInterval(TO_CHAR(datestamp, 'YYYY-WW')); 
    ELSE 
     RETURN NULL; 
    END IF; 
END; 

として行われることになるそのハードは、そのモジュールが何をするか知っているので、TReportIntervalが何をするかわかりません。 私はGET_INTERVAL_SEQUENCE_UDFを置き換えるためにPIPELINED PL/SQL関数を見ています。そのような問題に直面することの難しさは、オプティマイザが返す行の数が決して適切でないため、間違っていることがよくあります。

Get_Context_Info_udfでも同様の問題が発生します。 1行または10,000を返すかどうかは明白ではありません。再び、TTrfrmEngMachineInfoは完全に不透明です。

賢明には、オプティマイザがクエリを最適に処理する方法を知らないようにするために、可能な限りすべてが行われています。

統計表が主なものであれば、私はあなたがCONTEXT_IDに基づいvalue_numericをまとめた

WHERE 
     StatisticTypeID = HEXTORAW ('6CF933B091AE46FEA7F56BE96308190F') 
     AND EntryDate < TO_TIMESTAMP ('07/20/2011','mm/dd/yyyy') 
     AND EntryDate > TO_TIMESTAMP ('07/15/2011', 'mm/dd/yyyy') 

に基づいてテーブルをフィルタリングしていると思います。

多分日付ディメンション全体概要(おそらく毎日/毎週/毎月の合計?)

私が試してみたし、可能な限り多くのPL/SQLを取り除くのいくつかの並べ替え。統計から簡単なクエリを開始し、各段階で何をしたいかを記述します。

+0

TReportIntervalは、TReportIntervalListが定義されている型です。そのため、私はIFではなく、大文字小文字を使用してselectを行いました。戻り値の型が関数型と一致しないため、表示した文はコンパイルされません。ユーザー定義型を使用する際のポイントは、CROSS APPLY(TSQL)として使用でき、それをグループ化して統計のロールアップを完了できることでした。 – tafaju

関連する問題