gia*_*cum 1 performance cte execution-plan view sql-server-2012
我需要你的帮助,我需要一些指导来提高以下给定视图的性能。
我有一个用以下代码编写的视图:
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
Run Code Online (Sandbox Code Playgroud)
最重要的部分是搜索结果 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;
Run Code Online (Sandbox Code Playgroud)
如果您查看查询计划,就会发现对基表进行了 3 次扫描——一次用于初始表FROM,一次用于每个表JOIN。一共是三个。
这在几个地方引起了问题:
transactionsCTEtransactions在searchResultsCOUNT最终选择中的所有子查询searchresults这导致了你的第二个问题:CASE你用来计算你的FROM和TO日期的这两个表达式是完全非 SARGable 的。
您有两个选择:
将你的第一个 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;
Run Code Online (Sandbox Code Playgroud)
您可以为这些列建立索引,以dbo.ixf_transaction提高连接效率,避免必须预处理所有数据然后再连接。
而且我倾向于使用临时表来保留searchResults. 这可以防止对每个CASE表达式重新执行的需要。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
5206 次 |
| 最近记录: |