22

したがって、SELECTに一連のCASEステートメントを必要とするクエリがあります。これは元の設計ではなく、妥協の一部でした。

したがって、クエリは次のようになります。

SELECT
  CONT.TABLE.FINC_ACCT_NM,
  CONT.TABLE.FINC_ACCT_ID,
  CONT.TABLE.CURR_END_OF_PERD_ACTL_VAL,
  CONT.TABLE.PREV_END_OF_PERD_ACTL_VAL,
  CONT.TABLE.VARNC_PLAN_VAL,
  CONT.TABLE.OUTLOOK_BDGT_PLAN_VAL,
  CONT.TABLE.PERD_END_RPT_DT,
  CONT.TABLE.PLAN_VERS_NM,
  CONT.TABLE.FRMT_ACTL_CD,
  CONT.TABLE.FRMT_PLAN_CD,
  CONT.TABLE.RPT_PERD_TYPE_CD,
  CASE 
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Net Interest Income'  
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Non Interest Income'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Non-Interest Expense'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Total Marketing Expense'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Total Operating Expense'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Pre-Provision Earnings (before tax)'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Net Charge-offs'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Other'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      '  Allowance Build (Release)'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Provision Expense'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Pretax Income'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Tax Expense'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'NIAT'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'EPS'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Ending Loans - HFI'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'avg'       then      'Average Loans - HFI'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'avg'       then      'Average Earning Assets'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Ending Deposits'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'avg'       then      'Average Deposits'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'NIM on Loans'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Revenue Margin'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'AC579'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Charge off rate'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Efficiency ratio'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'ROA'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'ROE'
                WHEN ( CONT.TABLE.FINC_ACCT_ID )=           'XXXX'        and ( CONT.TABLE.BAL_TYPE_CD ) =             'EOP'      then      'Return on Allocated Capital (ROAC)'



  ELSE ( CONT.TABLE.FINC_ACCT_NM ) end
FROM
  CONT.TABLE
WHERE
  (
   (
    ( ( CONT.TABLE.PERD_END_RPT_DT ) = (

SELECT Max(Perd_END_RPT_DT) 
FROM CONT.TABLE
Where VERS_NM='Actual'
   AND RPT_PERD_TYPE_CD = 'Q'
   AND DATA_VLDTN_IND='Y'
)
   AND RPT_PERD_TYPE_CD = 'Q'
  AND DATA_VLDTN_IND='Y'  )
    OR
    ( ( CONT.TABLE.PERD_END_RPT_DT ) = (

SELECT Max(Perd_END_RPT_DT) 
FROM CONT.TABLE
Where VERS_NM='Actual'
   AND RPT_PERD_TYPE_CD = 'M'
   AND DATA_VLDTN_IND='Y'
) 

  AND RPT_PERD_TYPE_CD = 'M'
  AND DATA_VLDTN_IND='Y'  )
   )
   AND
   ( ( CONT.TABLE.DATA_VLDTN_IND )='Y'  )
   AND
   ( ( CONT.TABLE.FINC_ACCT_ID )IN ('AC0006470','AC8000199','AC8002145','AC0006586','AC8000094')  AND ( CONT.TABLE.DEPT_ID )='OR80637'  )
  )

私の質問は、これらすべてのCASEステートメントを直接列参照に変更するとパフォーマンスにどのような影響があるかということです。

言い換えると、すべてのCASEステートメントを列名だけに変更し、クエリからすべてのCASEステートメントを削除した場合、パフォーマンスに大きな影響がありますか。その理由は何ですか。

パフォーマンスが影響を受けるかどうかを判断できるようにこれをテストしていますが、なぜの詳細にも同じように興味がありますか?(理由の技術的な詳細)

ご協力いただきありがとうございます!

4

2 に答える 2

25

caseステートメントは、WHERE句の結合よりもはるかに少ない要素になります。

SQLのパフォーマンスの主な推進要因は、I /O(ディスクからデータを読み取ること)です。私はそれを、行で行われる処理よりも2桁重要だと考えています。これは単なるヒューリスティックであり、データベースでの特定のテストに基づくものではありません。

自己結合を実行しているため、テーブルを読み取るための多くの作業か、インデックスを処理するためのかなりの量の作業が必要になります。

一方、caseステートメントは、equals、gotosなどの非常に原始的なハードウェアコマンドに変換されます。データはプロセッサに最も近いメモリに存在するため、圧縮されます。あなたはcaseステートメント(likeやsubqueryなど)で特別なことは何もしていません。ステートメントのほとんどの行を削除した場合、クエリは同じくらい高速になると思います。

パフォーマンスに問題がある場合は、(VERS_NM、RPT_PERD_TYPE_CD、DATA_VLDTN_IND、Perd_END_RPT_DT)にインデックスを付けます。この4つの部分からなるインデックスにより、元のテーブルでI/O要求を呼び出さなくても最大日付を取得できます。

于 2012-08-17T20:49:41.387 に答える
9

編集:実際には、これらのサブクエリの両方をリファクタリングしてJOIN、とにかく高速になる可能性があります。それも多くの繰り返しを取り除きます!

これは実際にはクエリのパフォーマンスに関するものではありませんが(@Gordonはそれをかなりうまくカバーしています)、その巨大なcaseステートメントはメンテナンスの悪夢のように思えます。たぶんそれを処理するためのより良い方法はそれをテーブルに変換することでしょう

CREATE TABLE ACCT_DISPLAY_NAME (
    FINC_ACCT_ID CHAR(10),
    BAL_TYPE_CD  CHAR(3),
    DISPLAY_NAME VARCHAR(100)
);

CREATE INDEX ACCT_DISPLAY_INDEX ON ACCT_DISPLAY_NAME (
    FINC_ACCT_ID,
    BAL_TYPE_CD
);

INSERT INTO ACCT_DISPLAY_NAME VALUES
('AC99800'  , 'EOP', '  Net Interest Income'               ),
('AC12993'  , 'EOP', '  Non Interest Income'               ),
('AC667999' , 'EOP', 'Non-Interest Expense'                ),
('AC996587' , 'EOP', '  Total Marketing Expense'           ),
('AC659986' , 'EOP', '  Total Operating Expense'           ),
('AC69678'  , 'EOP', 'Pre-Provision Earnings (before tax)' ),
('AC09994'  , 'EOP', '  Net Charge-offs'                   ),
('AC20977'  , 'EOP', '  Other'                             ),
('AC19979'  , 'EOP', '  Allowance Build (Release)'         ),
('AC7094'   , 'EOP', 'Provision Expense'                   ),
('AC6997'   , 'EOP', 'Pretax Income'                       ),
('AC0994'   , 'EOP', 'Tax Expense'                         ),
('AC9999'   , 'EOP', 'NIAT'                                ),
('AC7990'   , 'EOP', 'EPS'                                 ),
('AC9995'   , 'EOP', 'Ending Loans - HFI'                  ),
('AC9995'   , 'avg', 'Average Loans - HFI'                 ),
('AC2991'   , 'avg', 'Average Earning Assets'              ),
('AC2999'   , 'EOP', 'Ending Deposits'                     ),
('AC9999'   , 'avg', 'Average Deposits'                    ),
('AC0379'   , 'EOP', 'NIM on Loans'                        ),
('AC6999'   , 'EOP', 'Revenue Margin'                      ),
('AC579'    , 'EOP', 'Charge off rate'                     ),
('AC5899'   , 'EOP', 'Efficiency ratio'                    ),
('AC629'    , 'EOP', 'ROA'                                 ),
('AC359'    , 'EOP', 'ROE'                                 ),
('AC619'    , 'EOP', 'Return on Allocated Capital (ROAC)'  );

そして、LEFT JOINそれに(あなたはそれを持っているのでELSECASE、次のようなことをします:

SELECT T.FINC_ACCT_NM,
       T.FINC_ACCT_ID,
       T.CURR_END_OF_PERD_ACTL_VAL,
       T.PREV_END_OF_PERD_ACTL_VAL,
       T.VARNC_PLAN_VAL,
       T.OUTLOOK_BDGT_PLAN_VAL,
       T.PERD_END_RPT_DT,
       T.PLAN_VERS_NM,
       T.FRMT_ACTL_CD,
       T.FRMT_PLAN_CD,
       T.RPT_PERD_TYPE_CD,
       COALESCE(N.DISPLAY_NAME, T.FINC_ACCT_NM)

FROM CONT.TABLE T
JOIN (
    SELECT RPT_PERD_TYPE_CD, DATA_VLDTN_IND, Max(Perd_END_RPT_DT) AS PERD_END_RPT_DT
    FROM CONT.TABLE
    WHERE VERS_NM='Actual'
      AND DATA_VLDTN_IND='Y'
    GROUP BY RPT_PERD_TYPE_CD, DATA_VLDTN_IND
) AS MAX_DATES
  ON T.RPT_PERD_TYPE_CD = MAX_DATES.RPT_PERD_TYPE_CD
 AND T.DATA_VLDTN_IND   = MAX_DATES.DATA_VLDTN_IND 
 AND T.PERD_END_RPT_DT  = MAX_DATES.PERD_END_RPT_DT 

LEFT JOIN ACCT_DISPLAY_NAME N
  ON T.FINC_ACCT_ID = N.FINC_ACCT_ID
 AND T.BAL_TYPE_CD  = N.BAL_TYPE_CD

WHERE T.DEPT_ID = 'OR80637'

  AND T.RPT_PERD_TYPE_CD IN ('Q', 'M')

  AND T.FINC_ACCT_ID IN (
    'AC0006470',
    'AC8000199',
    'AC8002145',
    'AC0006586',
    'AC8000094'
  )
于 2012-08-17T21:04:42.723 に答える