私はあなたの助けが必要です、次の与えられたビューのパフォーマンスを改善するためにいくつかのガイダンスが必要です。
私は以下のコードで書かれたビューを持っています:
with timeframes as
(
select p.SEARCH_NUM,
case when p.FROM_DATE is not null then p.FROM_DATE
when p.FROM_DATE is null and P.SEARCH_DAYS is not null and p.TO_DATE is not null then DATEADD(day,p.SEARCH_DAYS*-1,p.TO_DATE)
when p.FROM_DATE is null and P.SEARCH_DAYS is not null and p.TO_DATE is null then DATEADD(day,p.SEARCH_DAYS*-1,GetDate())
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is not null and p.DURATION = 'Yearly' then DATEADD(year,-1,p.TO_DATE)
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is null and p.DURATION = 'Yearly' then DATEADD(year,-1,GetDate())
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is not null and p.DURATION = 'Monthly' then DATEADD(month,-1,p.TO_DATE)
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is null and p.DURATION = 'Monthly' then DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is not null and p.DURATION = 'Weekly' then DATEADD(day,-7,p.TO_DATE)
when p.FROM_DATE is null and P.SEARCH_DAYS is null and p.TO_DATE is null and p.DURATION = 'Weekly' then DATEADD(day,-7,GetDate())
else DATEADD(month,-1,GetDate())
end as FROM_DATE
,case when p.TO_DATE is not null then p.TO_DATE
when p.TO_DATE is null and p.DURATION = 'Monthly' then DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
else GetDate()
end as TO_DATE
from dbo.parmeters_table as p
)
,
transactions as
(
select tm.SEARCH_NUM, tr.id from dbo.ixf_transaction tr
inner join timeframes tm on tr.transaction_date between tm.FROM_DATE and tm.TO_DATE
)
,
searchResults AS
(
select DISTINCT
t.SEARCH_NUM
,trx.id as 'trx_id_FK'
,trx.institution_FK
,trx.branch_FK
,branch.code as 'branch_number'
,trx.account_FK
,trx.transaction_date as 'trx_date'
,case when trx.type_of_transaction = 'I' or trx.type_of_transaction = 'B'
then trx.base_currency_amount else 0 end as 'cash_in'
,case when trx.type_of_transaction = 'O' or trx.type_of_transaction = 'B'
then trx.base_currency_amount else 0 end as 'cash_out'
,case when trx.type_of_transaction = 'B'
then trx.base_currency_amount else 0 end as 'curr_exchange'
,trx.base_currency_amount
,trx.type_of_transaction
,trx.teller_id
,trx.unique_trans_id
,trx.serial_number
,trx.foreign_amount
,trx.country_of_currency_FK
,trx.flex_1
,trx.flex_2
,trx.customer_FK
,ttr.code as 'trx_code'
,ttr.description as 'trx_description'
,ttr.irs_transaction_id
,cust.full_name
,str(cust.web_reference_id) as 'web_reference_id'
,conben.customer_cif
,conben.id_number
,conben.id_type
,conben.other_description as 'id_type_other_description'
,conben.customer_tin
,conben.cust_type_fk as 'TIN_Type'
,ctrtx.is_teller
from ixf_transaction trx
inner join transactions t on trx.id = t.id
inner join type_ref ttr on ttr.id=trx.transaction_type_FK
inner join unit branch on branch.id=trx.branch_FK and branch.object_type='Branch'
left join cust on cust.id = trx.customer_FK
left join cashtx_cus conben on conben.transaction_id = trx.unique_trans_id and conben.customer_FK = trx.customer_FK
left join trans ctrtx on ctrtx.cash_transaction_fk = trx.id
)
select trx_id_fk
,case when account_FK is not null then (select count(1) from searchresults a where a.account_fk = searchresults.account_fk and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select count(1) from searchresults a where a.customer_cif = searchresults.customer_cif and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select count(1) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select count(1) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select count(1) from searchresults a where a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'trx_per_period'
,case when account_FK is not null then (select count(1) from searchresults a where a.account_FK = searchresults.account_FK and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select count(1) from searchresults a where a.customer_cif = searchresults.customer_cif and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select count(1) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select count(1) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select count(1) from searchresults a where a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'trx_per_day'
,case when account_FK is not null then (select sum(cash_in) from searchresults a where a.account_FK = searchresults.account_FK and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select sum(cash_in) from searchresults a where a.customer_cif = searchresults.customer_cif and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select sum(cash_in) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select sum(cash_in) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select sum(cash_in) from searchresults a where a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'total_per_day_cash_in'
,case when account_FK is not null then (select sum(cash_out) from searchresults a where a.account_FK = searchresults.account_FK and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select sum(cash_out) from searchresults a where a.customer_cif = searchresults.customer_cif and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select sum(cash_out) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select sum(cash_out) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select sum(cash_out) from searchresults a where a.trx_date = searchresults.trx_date and a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'total_per_day_cash_out'
,case when account_FK is not null then (select sum(cash_in) from searchresults a where a.account_FK = searchresults.account_FK and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select sum(cash_in) from searchresults a where a.customer_cif = searchresults.customer_cif and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select sum(cash_in) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select sum(cash_in) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select sum(cash_in) from searchresults a where a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'total_per_period_cash_in'
,case when account_FK is not null then (select sum(cash_out) from searchresults a where a.account_FK = searchresults.account_FK and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_cif is not null then (select sum(cash_out) from searchresults a where a.customer_cif = searchresults.customer_cif and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when customer_tin is not null then (select sum(cash_out) from searchresults a where a.customer_tin = searchresults.customer_tin and a.TIN_Type = searchresults.TIN_Type and a.SEARCH_NUM = searchresults.SEARCH_NUM)
when ID_NUMBER is not null then (select sum(cash_out) from searchresults a where a.ID_NUMBER = searchresults.ID_NUMBER and a.SEARCH_NUM = searchresults.SEARCH_NUM)
else (select sum(cash_out) from searchresults a where a.SEARCH_NUM = searchresults.SEARCH_NUM)
end as 'total_per_period_cash_out'
from SearchResults
重要な部分は、何度も何度も呼び出される検索結果cteです。実行プランは次のようになります。
同じ結果セットを取得してそれを回避し、その重い実行計画を回避する方法はありますか?
誤った仮定の下でコードを記述している可能性があります。CTEの結果は保持されます
そうではない 、そしてそれらを参照するたびに、構文が再実行されます。
ここに簡単な例があります:
CREATE TABLE #dummy
(
id INT
);
INSERT #dummy ( id )
VALUES ( 1 );
WITH yourmom
AS ( SELECT d.id
FROM #dummy AS d )
SELECT ym.id
FROM yourmom AS ym
JOIN yourmom AS ym2
ON ym2.id = ym.id
JOIN yourmom AS ym3
ON ym3.id = ym.id;
クエリプラン を見ると、ベーステーブルのスキャンが3回あります。最初のFROM
と各JOIN
のスキャンです。合計で3つです。
これはいくつかの場所で問題を引き起こしています:
transactions
CTEへの参加transactions
内のsearchResults
COUNT
からの最終選択内のすべてのsearchresults
サブクエリそれが2番目の問題につながります。CASE
とFROM
の日付を計算するために使用する2つのTO
式は完全に non-SARGable です。
次の2つのオプションがあります。
最初のCTEの結果を#temp table
に貼り付けます
計算された列をベーステーブルに追加する
この場合、おそらく計算された列を選択します
ALTER TABLE dbo.parmeters_table
ADD FROM_DATE_SEARCHED AS CASE WHEN FROM_DATE IS NOT NULL THEN FROM_DATE
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NOT NULL
AND TO_DATE IS NOT NULL THEN DATEADD(DAY, SEARCH_DAYS * -1, TO_DATE)
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NOT NULL
AND TO_DATE IS NULL THEN DATEADD(DAY, SEARCH_DAYS * -1, GETDATE())
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NOT NULL
AND DURATION = 'Yearly' THEN DATEADD(YEAR, -1, TO_DATE)
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NULL
AND DURATION = 'Yearly' THEN DATEADD(YEAR, -1, GETDATE())
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NOT NULL
AND DURATION = 'Monthly' THEN DATEADD(MONTH, -1, TO_DATE)
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NULL
AND DURATION = 'Monthly' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0)
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NOT NULL
AND DURATION = 'Weekly' THEN DATEADD(DAY, -7, TO_DATE)
WHEN FROM_DATE IS NULL
AND SEARCH_DAYS IS NULL
AND TO_DATE IS NULL
AND DURATION = 'Weekly' THEN DATEADD(DAY, -7, GETDATE())
ELSE DATEADD(MONTH, -1, GETDATE())
END,
TO_DATE_SEARCHED AS CASE WHEN TO_DATE IS NOT NULL THEN TO_DATE
WHEN TO_DATE IS NULL
AND DURATION = 'Monthly' THEN DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()) - 1, -1)
ELSE GETDATE()
END;
これらの列にインデックスを付けて、dbo.ixf_transaction
への結合をより効率的にし、すべてのデータを前処理してから結合する必要をなくすことができます。
そして、searchResults
の結果を永続化するために、一時テーブルを使用します。これにより、各CASE
式を再実行する必要がなくなります。
お役に立てれば!
同じ結果セットを取得してそれを回避し、その重い実行計画を回避する方法はありますか?
Cte searchresultからの結果を一時テーブルに永続化して、代わりにメインクエリで一時テーブルを使用してください
一言で言えば、あなたは一度にすべてをやりすぎているようです:o)
最後にある最後の大きなSELECT
は、すべての並列CASE
式で、問題の一部です。その1つのビューの下にすべてのものを作成し、最後にその大きなクエリを1つのJOIN
に対して(ON
句の条件を使用して)分割するか、場合によっては5つの個別のクエリに一致させる必要がありますそれらの条件のそれぞれ。どちらにしても、本当に、場合によってはこれらの副選択を取り除きたいです(特に、何かを見逃していない限り、SUM
のすべてのブランチで同じ列のCASE
を実行しているように見えるため) )。
編集:わかりました、早すぎる話ですが、一部のサブ選択で異なる条件があるようですが、それでも、2つのJOINS
に減らすことができます。 a.trx_date = searchresults.trx_date
条件が必要なデータと不要なデータ用。この時点でデータをよく理解していると思いますので、私は自分の深みから離れて歩き続けるつもりはありません。
おそらくCASE
CTEのtimeframes
ブランチのいくつかをCOALESCE
に変えますが、それはスタイルや好みの問題です。