I am looking for some tips/tricks to improve performance of a stored procedure with multiple SELECT statements inserting into a table. All objects I am joining on are already indexed.
I believe the reason this stored procedure takes almost an hour to run is because there are multiple SELECT statements using following two views: rvw_FinancialLineItemValues and rvw_FinancialLineItems
Also, each SELECT statement uses specific hard-coded values for AccountNumber, LineItemTypeID, and few other field values coming from two views mentioned above.
Would it improve performance if I create a temporary table, which gets ALL data needed for these SELECT statements at once and then using this temporary table in my join instead?
Are there any other ways to improve performance and manageability?
SELECT
@scenarioid,
@portfolioid,
pa.Id,
pa.ExternalID,
(select value from fn_split(i.AccountNumber,'.') where id = 1),
ac.[Description],
cl.Name,
NullIf((select value from fn_split(i.AccountNumber,'.') where id = 2),''),
NullIf((select value from fn_split(i.AccountNumber,'.') where id = 3),''),
ty.Name,
v.[Date],
cast(SUM(v.Amount) as decimal(13,2)),
GETDATE()
FROM rvw_FinancialLineItems i
INNER JOIN rvw_Scenarios sc
ON i.ScenarioId = sc.Id
AND sc.Id = @scenarioid
AND sc.PortfolioId = @portfolioid
INNER JOIN #pa AS pa
ON i.PropertyAssetID = pa.Id
INNER JOIN rvw_FinancialLineItemValues v
ON i.ScenarioId = v.ScenarioId
AND i.PropertyAssetID = v.PropertyAssetID
AND i.Id = v.FinancialLineItemId
AND ((i.BusinessEntityTypeId = 11
AND i.LineItemTypeId = 3002)
OR (i.LineItemTypeId IN (2005, 2010, 2003, 2125, 2209, 5012, 6001)
AND i.ModeledEntityKey = 1))
AND i.AccountNumber not in ('401ZZ','403ZZ')
AND i.AccountNumber not in ('401XX')
AND i.AccountNumber not in ('40310','41110','42010','41510','40190','40110') -- exclude lease-level revenues selected below
AND v.[Date] BETWEEN @fromdate AND
CASE
WHEN pa.AnalysisEnd < @todate THEN pa.AnalysisEnd
ELSE @todate
END
AND v.ResultSet IN (0, 4)
INNER JOIN rvw_Portfolios po
ON po.Id = @portfolioid
INNER JOIN Accounts ac
ON po.ChartOfAccountId = ac.ChartOfAccountId
AND i.AccountNumber = ac.AccountNumber
AND ac.HasSubAccounts = 0
INNER JOIN fn_LookupClassTypes() cl
ON ac.ClassTypeId = cl.Id
INNER JOIN LineItemTypes ty
ON ac.LineItemTypeId = ty.Id
LEFT JOIN OtherRevenues r
ON i.PropertyAssetID = r.PropertyAssetID
AND i.AccountNumber = r.AccountID
AND v.[Date] BETWEEN r.[Begin] AND r.[End]
WHERE (r.IsMemo IS NULL
OR r.IsMemo = 0)
GROUP BY pa.AnalysisBegin
,pa.Id
,pa.ExternalID
,i.AccountNumber
,ac.[Description]
,cl.Name
,ty.Name
,v.[Date]
HAVING SUM(v.amount) <> 0
You should run your query with SET SHOWPLAN ALL ON
or with Management Studio Save Execution Plan
and look for inefficiencies.
There are some resources online that help in analyzing the results, such as: http://www.sqlservercentral.com/articles/books/65831/
I would look to the following first. What are the wait types relevant to your stored procedure here? Are you seeing a lot of disk io time? Are things being done in memory? Maybe there's network latency pulling that much information.
Next, what does the plan look like for the procedure, where does it show all the work is being done?
The views definitely could be an issue as you mentioned. You could maybe have pre-processed tables so you don't have to do as many joins. Specifically the joins where you are seeing the most amount of CPU spent.
Correlated subqueries are generally slow and should never be used when you are trying for performance. Use the fn_split to create a temp table Index it if need be and then join to it to get the value you need. You might need to join multiple times for different value, without actually knowing the data I am having a hard time visualizing.
It is also not good for performance to use OR. Use UNION ALL in a derived table instead.
Since you have all those conditions on the view rvw_FinancialLineItems, yes it might work to pull those out to a temp table and then index the temp table.
YOu might also see if using the views is even a good idea. Often views have joins to many table that you aren't getting data from and thus are less performant than querying only the tables you actually need. This is especially true if your organization was dumb enough to make views that call views.
First thing, which fn_split()
UDF are you using? If you are not using the table-Valued inline UDF, then this is notoriously slow.
Second, is the UDF fn_LookupClassTypes()
an inline table valued UDF? If not, convert it to an inline Table-Valued UDF.
Last, your SQL query had some redundancies. Try this and see what it does.
SELECT @scenarioid, @portfolioid, pa.Id, pa.ExternalID,
(select value from fn_split(i.AccountNumber,'.')
where id = 1), ac.[Description], cl.Name,
NullIf((select value from fn_split(i.AccountNumber,'.')
where id = 2),''),
NullIf((select value from fn_split(i.AccountNumber,'.')
where id = 3),''), ty.Name, v.[Date],
cast(SUM(v.Amount) as decimal(13,2)), GETDATE()
FROM rvw_FinancialLineItems i
JOIN rvw_Scenarios sc ON sc.Id = i.ScenarioId
JOIN #pa AS pa ON pa.Id = i.PropertyAssetID
JOIN rvw_FinancialLineItemValues v
ON v.ScenarioId = i.ScenarioId
AND v.PropertyAssetID = i.PropertyAssetID
AND v.FinancialLineItemId = i.Id
JOIN rvw_Portfolios po ON po.Id = sc.portfolioid
JOIN Accounts ac
ON ac.ChartOfAccountId = po.ChartOfAccountId
AND ac.AccountNumber = i.AccountNumber
JOIN fn_LookupClassTypes() cl On cl.Id = ac.ClassTypeId
JOIN LineItemTypes ty On ty.Id = ac.LineItemTypeId
Left JOIN OtherRevenues r
ON r.PropertyAssetID = i.PropertyAssetID
AND r.AccountID = i.AccountNumber
AND v.[Date] BETWEEN r.[Begin] AND r.[End]
WHERE i.ScenarioId = @scenarioid
and ac.HasSubAccounts = 0
and sc.PortfolioId = @portfolioid
and IsNull(r.IsMemo, 0) = 0)
and v.ResultSet In (0, 4)
and i.AccountNumber not in
('401XX', '401ZZ','403ZZ','40310','41110',
'42010','41510','40190','40110')
and v.[Date] BETWEEN @fromdate AND
CASE WHEN pa.AnalysisEnd < @todate
THEN pa.AnalysisEnd ELSE @todate END
and ((i.LineItemTypeId = 3002 and i.BusinessEntityTypeId = 11) OR
(i.ModeledEntityKey = 1 and i.LineItemTypeId IN
(2005, 2010, 2003, 2125, 2209, 5012, 6001)))
GROUP BY pa.AnalysisBegin,pa.Id, pa.ExternalID, i.AccountNumber,
ac.[Description],cl.Name,ty.Name,v.[Date]
HAVING SUM(v.amount) <> 0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.