web-dev-qa-db-ja.com

SQL-SELECTに複数のCASEステートメントがあることによるパフォーマンスへの影響-Teradata

そのため、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ステートメントをクエリから削除した場合、パフォーマンスに大きな影響がありますが、それはなぜですか。

これをテストして、パフォーマンスに影響があるかどうかを確認できるようにしましたが、なぜ同じように詳細に関心がありますか? (理由の技術的詳細)

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

19
tarheels058

Caseステートメントは、WHERE句の結合よりもはるかに重要ではありません。

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

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

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

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

21
Gordon Linoff

編集:実際には、これらのサブクエリの両方をJOINにリファクタリングできます。たくさんの繰り返しも解消します!

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

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'
  )
8
bhamby