このクエリは、最後に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'
)
実行計画 ここ 。
インデックスがほとんどないようです。これがサードパーティのアプリではない場合、ここでテストするインデックスをいくつか示します。 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/
今のところ、これに時間をかけすぎました。テスト環境でこれらのインデックスを試して、どれだけの違いがあるかを確認してください。これらの種類の変更を行うことができ、知らない場合は、インデックス作成を紹介するブログ投稿を探し始める必要があります。
IMO、クエリは最適化されていません。インデックスのチューニングには適していません。
一部のインデックスは一時的に緩和されます。
また、テーブルデザイン、データ、および要件がないため、クエリを書き換えることはできません。
だから私の質問はただあなたにアイデアを与えるためのものですが、私は私のアイデアについて100%確信しています。
私のおすすめ、
Join
の目的で、クエリでReadability
を明示的に使用します。どのテーブルがどのテーブルとどの列に接続されているかを把握するのは困難です。
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倍向上します。
この時点で、インデックスのチューニングまたはさらに改善するためのクエリとして表示できます。