0

DB2 SQL で奇妙な動作が発生しています。(DB2 9.7) 以下は、従業員の給与、ステータス、バンドを取得するサンプル クエリです。

SELECT
                EMP.STATUS,
                COUNT(*)               AS EMP_COUNT,
                GRP.GROUP_NAME
FROM
                EMPLOYEE EMP,
                EMPLOYEE_SALARY ES,
                GROUP_TABLE GRP
WHERE
                EMP.SALARY > 
                             (select max(EMP1.SALARY) from  
                             EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
                              date(EMP1.JOIN_DT) = '2013-01-01' 
                              and date(EMP1.DATE_TS) = date(FY.CURRENT_DT) - 2 days)
                AND EMP.SALARY = E.EMPID
                AND E.SALARY_GRP = GRP.BAND_GROUP
                AND GRP.RANGE_SALARY = 'BAND-10'
                GROUP BY
                        EMP.STATUS,
                        GRP.GROUP_NAME

EMP (従業員) テーブルには、約 100 万行が含まれています。残りのテーブルは非常に小さいです。クエリの実行には約 10 秒かかります

しかし、内部クエリをハードコーディングすると

から

select max(EMP1.SALARY) from  EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
        date(EMP1.JOIN_DT) = '2013-01-01' 
        and date(EMP1.DATE_TS) = date(FY.CURRENT_DT) - 2 days

select max(EMP1.SALARY) from  EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
       date(EMP1.JOIN_DT) = '2013-01-01' 
       and date(EMP1.DATE_TS) = '2013-06-01' 

結果は1秒以内に来ます!!

「FINANCIAL_YEAR FY」テーブルは約50行の非常に小さなテーブルであるため、動的なときに内部クエリに時間がかかる理由がわかりませんが、ハードコーディングすると非常に高速です

いくつかの追加情報

  • EMPID は整数です
  • DATE_TS はタイムスタンプです
  • CURRENT_DT、JOIN_DT は日付
  • 残りはすべて VARCHAR です
  • EMPID は索引付けされています
4

1 に答える 1

0

このバージョンを試すことができます (E参照はESエイリアスであると想定しています。そうでない場合、ステートメントは実行されません)。FROMとりわけ、特に s を扱い始める場合は、「暗黙の結合」(コンマ区切り句) を捨てる必要がありますLEFT JOIN

WITH Maximum_Salary (max) as (SELECT MAX(EMP.SALARY) 
                              FROM EMPLOYEE EMP
                              JOIN FINANCIAL_YEAR FY
                                ON (FY.CURRENT_DT - 2 DAYS) >= EMP.DATE_TS
                                   AND (FY.CURRENT_DT - 1 DAYS) < EMP.DATE_TS
                              WHERE EMP.JOIN_DT = DATE('2013-01-01')

SELECT EMP.STATUS, COUNT(*) AS EMP_COUNT, GRP.GROUP_NAME
FROM EMPLOYEE EMP
JOIN GROUP_TABLE GRP
  ON GRP.RANGE_SALARY = 'BAND-10'
JOIN EMPLOYEE_SALARY ES
  ON ES.EMPID = EMP.SALARY
     AND ES.SALARY_GRP = GRP.BAND_GROUP
JOIN Maximum_Salary 
  ON Maximum_Salary <= EMP.SALARY
GROUP BY EMP.STATUS, GRP.GROUP_NAME

まだ慣れていない場合、WITH構文は Common Table Expression (または CTE) です。事実上、これはインライン ビューです。これらにより、場合によっては一時テーブルが作成される可能性がありますが、それ以外の場合は、多くの入力を節約できます (再帰クエリの実行方法でもあります)。への参照をEMP.DATE_TS、インデックスを使用できる形式にすることができました (FY.CURRENT_DTあまり重要ではない小さなテーブルとしてではありますが、 の日付計算には何の助けにもなりません)。

特に、持っている (持っていない) インデックスによっては、追加のチューニングを実行する必要があるかもしれないことに注意してください。

于 2013-06-03T17:26:39.497 に答える