web-dev-qa-db-ja.com

自己結合の最適化を支援する

このクエリは、最後にWHERE IN()ステートメントがあるため、必要な時間の5倍以上かかります。私は頭の中のジュニアDBAで、それを最適化する方法を見つけようとしています。外部クエリの結果セットをIN()でチェックする方法はありますか?自己結合のいずれかを組み合わせることができますか?推奨するクエリ最適化リソースはありますか?

ミニマリズム、完全性、検証可能性の欠如に対する謝罪-DDLを含めて、やりすぎのように見えました。以下は、クエリと実行プランのボトルネックです。

SELECT SC.ROW_ID      C1_CASE_ID,
       SC2.ROW_ID     C2_NEW_CASE_ID,
       SC2.CASE_NUM   C3_NEW_CASE_NUM,
       MC.ROW_ID      C4_MSTR_CASE_ID,
       MC2.ROW_ID     C5_NEW_MSTR_CASE_ID,
       MC2.CASE_NUM   C6_NEW_MSTR_CASE_NUM
 FROM  siebel.ODS_S_CONTACT          MCON2, 
       siebel.ODS_S_CONTACT          MCON, 
       siebel.ODS_S_CASE             SC, 
       siebel.ODS_S_CASE             MC, 
       siebel.ODS_S_CASE_BNFTPLAN    CBP, 
       siebel.ODS_S_CASE             MC2, 
       siebel.ODS_S_CASE             SC2
WHERE (SC.STATUS_CD = 'Withdrawn')
  AND (CBP.STATUS_CD IN ('Active', 'Approved','Inactive') 
  AND EXISTS (
               SELECT 1 
                 FROM (SELECT cbp2.row_id cbp2_row_id, 
                              cbp2.case_id cbp2_case_id,
                              DENSE_RANK() OVER (PARTITION BY cbp2.case_id ORDER BY CASE WHEN cbp2.status_cd = 'Active' THEN 1
                                                                                         WHEN cbp2.status_cd = 'Approved' THEN 2
                                                                                         WHEN cbp2.status_cd = 'Inactive' THEN 3
                                                                                         ELSE 4 
                                                                                    END,cbp2.created DESC
                                                ) cbp2_order
                         FROM siebel.ods_s_case_bnftplan cbp2
                      --where cbp2.case_id = CBP.CASE_ID
                      ) sq
                WHERE cbp2_order = 1
                  AND CBP.CASE_ID = cbp2_case_id
                  AND CBP.ROW_ID = cbp2_row_id
             )
      )
WHERE (SC.MSTR_CASE_ID=MC.ROW_ID)
  AND (MC.APPLICANT_ID=MCON.ROW_ID)
  AND (MCON.SOC_SECURITY_NUM=MCON2.SOC_SECURITY_NUM AND MCON.ROW_ID <> MCON2.ROW_ID)
  AND (MCON2.ROW_ID=MC2.APPLICANT_ID)
  AND (MC2.ROW_ID=SC2.MSTR_CASE_ID AND SC2.TYPE_CD = SC.TYPE_CD AND SC2.STATUS_CD = 'Active')
  AND (SC.ROW_ID=CBP.CASE_ID)
  AND SC2.CREATED IN (
                        -- default: 46 rows  ~30seconds
                        SELECT MAX(SCSUB.CREATED)
                          FROM siebel.ODS_S_CASE          SC2SUB
                         INNER JOIN siebel.ODS_S_CASE    MC2SUB        ON MC2SUB.ROW_ID = SC2SUB.MSTR_CASE_ID
                         INNER JOIN siebel.ODS_S_CONTACT MCON2SUB      ON MC2SUB.APPLICANT_ID = MCON2SUB.ROW_ID
                         INNER JOIN siebel.ODS_S_CONTACT MCONSUB       ON MCON2SUB.SOC_SECURITY_NUM = MCONSUB.SOC_SECURITY_NUM
                         INNER JOIN siebel.ODS_S_CASE    MCSUB         ON MCONSUB.ROW_ID = MCSUB.APPLICANT_ID
                         INNER JOIN siebel.ODS_S_CASE    SCSUB         ON MCSUB.ROW_ID = SCSUB.MSTR_CASE_ID 
                         INNER JOIN siebel.ODS_S_CASE_BNFTPLAN CBPSUB  ON CBPSUB.CASE_ID = SCSUB.ROW_ID
                         WHERE SC2SUB.ROW_ID = SC2.ROW_ID
                           AND  CBPSUB.STATUS_CD IN ('Active', 'Approved')
                           AND SC2SUB.TYPE_CD = SCSUB.TYPE_CD 
                           AND SCSUB.STATUS_CD = 'Active'
                      )

実行計画 ここ

Execution Plan

4
unsigned

インデックスがほとんどないようです。これがサードパーティのアプリではない場合、ここでテストするインデックスをいくつか示します。 Row_IDが一意の列であるなど、いくつかの仮定を行っています。

CREATE UNIQUE CLUSTERED INDEX CIX_OdsSCase_Sc2Sub_RowId ON ODS_S_Case.Sc2Sub
(
    RowId
)

CREATE INDEX IX_OdsSContact_Mcon2Sub_SocSecurityNum ON ODS_S_Contact.MCON2SUB
(
    Soc_Security_Num
)
INCLUDE
(
    Row_Id
)

CREATE INDEX IX_OdsSCaseBnftplan_Cbpsub_CaseId ON ODS_S_CASE_BNFTPLAN
(
    CASE_ID
)
INCLUDE
(
    STATUS_CD
)

CREATE INDEX IX_OdsSContact_Mconsub_SocSecurityNum ON ODS_S_CONTACT.MCONSUB
(
    Soc_Security_Num
)
INCLUDE
(
    Row_Id
)

CREATE INDEX IX_OdsSCase_Scsub_StatusCd_MstrCaseId ON ODS_S_CASE.SCSUB
(
    Status_Cd
    , Mstr_Case_Id
)
INCLUDE
(
    Row_Id
    , Created
    , Type_Cd
)

また、私は何も言わずにこれを見ることができません。暗号化されていない、一意であると想定して外部キーとして使用されている社会保障番号を持っているように見えます。これは多くのレベルでリスクです。私が見ているものが正しく、あなたが確信していない場合は、あなたが読むべき悪い考えです https://www.computerworld.com/article/2552992/not-so-unique.html そして https://helifromfinland.blog/2014/04/18/is-social-security-number-a-good-primary-key/

今のところ、これに時間をかけすぎました。テスト環境でこれらのインデックスを試して、どれだけの違いがあるかを確認してください。これらの種類の変更を行うことができ、知らない場合は、インデックス作成を紹介するブログ投稿を探し始める必要があります。

2
Steve Hood

IMO、クエリは最適化されていません。インデックスのチューニングには適していません。

一部のインデックスは一時的に緩和されます。

また、テーブルデザイン、データ、および要件がないため、クエリを書き換えることはできません。

だから私の質問はただあなたにアイデアを与えるためのものですが、私は私のアイデアについて100%確信しています。

私のおすすめ、

  1. Joinの目的で、クエリでReadabilityを明示的に使用します。

どのテーブルがどのテーブルとどの列に接続されているかを把握するのは困難です。

  1. 繰り返しの結果セットを保存するには、Temp tableを使用します。必要な情報がすべてわかっている場合は、CTEを使用することをお勧めします。

このようにして、オプティマイザは限られた結果セットを何度も処理する必要があります。

のように、siebel.ODS_S_CASE_BNFTPLANの値をこのフィルターと共に#BNFTPLANテーブルに入れることができます。

    CREATE table #BNFTPLAN(case_id int ,row_id int,status_cd int)

--Put  all columns of ODS_S_CASE_BNFTPLAN in this temp table that will be use in query along with status_cd as int

Insert into #BNFTPLAN(status_cd)
select 
WHEN cbp2.status_cd = 'Active' THEN 1    WHEN cbp2.status_cd = 'Approved' THEN 2
                                                 WHEN cbp2.status_cd = 'Inactive' THEN 3
                                                end 
from siebel.ODS_S_CASE_BNFTPLAN
where CBP.STATUS_CD IN ('Active', 'Approved','Inactive') 

-- Do not write DENSE_RANK logic in #BNFTPLAN
-- Notice I have omitted `ELSE 4`  from case because that is not required .
-- Because of this `where cbp2.case_id = CBP.CASE_ID`

私のコメントを読むことを忘れないでください。私のクエリは大雑把な作業にすぎないことを忘れないでください。完全に実装する必要があります。

siebel.ODS_S_CASEの値を#ODS_S_CASEテーブルに入れます

CREATE table #ODS_S_CASE(row_id int,CASE_NUM int,APPLICANT_ID int,TYPE_CD int,CREATED datetime)

-- In ODS_S_CASE carefully declare all columns which will be required in this query.

insert into #ODS_S_CASE(row_id,CASE_NUM,APPLICANT_ID,TYPE_CD,CREATED)
select row_id,CASE_NUM,APPLICANT_ID,TYPE_CD,CREATED from siebel.ODS_S_CASE sc
inner join #BNFTPLAN CBP
        on SC.ROW_ID=CBP.CASE_ID
--inner join MCON.ROW_ID
        where SC.STATUS_CD = 'Active'

Where条件SC.STATUS_CD = 'Active'を入れて#BNFTPLAN CBPに結合し、MCON.ROW_IDを使用しようとしていたことに注意してください

一時テーブルに挿入するときに条件と結合を慎重に適用すると、結果セットが制限されます。そのため、オプティマイザによって多くの行が何度も処理されません。

これにより、正確なCardianility Estimateが得られ、オプティマイザが正しい計画を立てるのに役立ちます。

これにより、クエリのパフォーマンスが3倍または5倍向上します。

この時点で、インデックスのチューニングまたはさらに改善するためのクエリとして表示できます。

0
KumarHarsh