So I just started working with SQL Server for about two months now (I am still a newbie), and I have to improve the performance of a stored procedure. It runs in 3sec but for somewhat reason the clients are not satisfied with the results. I have tried to train myself into reading the execution plans and figure out what are the problems.
After getting the SQL Sentry Plan Explorer, I figured out that only one part of the procedure is causing the problem, and that part is this:
With myAccount as
(
select
ROW_NUMBER() over(order by Account) as Row_ID,
ID, Account,
replace(Name, '*', '#_') Name,
Totaling
from
Account
where
Company_ID = @company_id and Balance = 0)
,myR1C1 (ID, R1C1) as
(
select
t1.ID,
case when t4.Account = t6.Account
then 'R[' + convert(nvarchar(10), t4.row_id - t1.Row_ID) + ']C'
else 'R[' + convert(nvarchar(10), t4.Row_ID - t1.Row_ID) + ']C:R[' + convert(nvarchar(10), t6.Row_ID - t1.Row_ID) + ']C'
end R1C1
--t1.*,t2.*,t4.*,t6.*, t4.id-t1.id,t6.id-t1.id
from
myAccount t1
cross apply
dbo.abx_sysSplitTwo(Totaling,'|') t2
cross apply
(select top 1
Row_ID, ID, account
from myAccount t3
where t3.account >= t2.VFr
and t3.account <= t2.vto
and t1.account <> t3.account
order by t3.account) t4
cross apply
(select top 1
Row_ID, ID, account
from myAccount t5
where t5.account >= t2.VFr
and t5.account <= t2.vto
and t1.account <> t5.account order by t5.account) t6
)
, myAccount2 as
(
Select
t1.*, t2.R1C1
from myAccount t1
left join
(select
ID, STUFF((select',' + R1C1
from myR1C1
where ID = a.id
for xml path ('')), 1, 1, '') as R1C1
from
myR1C1 as a
group by
id) t2 on t1.ID = t2.id
-- order by row_ID
-- Data1
select tv.id [<dang n="BudData" u="0" o="1" fmt="1" fn="ID"/>],tv.account, tv.Name
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,sum(case When tp.[Date] between dateadd(yy,-1,@FromDate) and dateadd(d,-1,@FromDate) then isnull(Bud,0) else 0 end)) end A
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,Sum(case When tp.[Date] between dateadd(yy,-1,@FromDate) and dateadd(d,-1,@FromDate) then isnull(tp.Actual,0) else 0 end)) end B
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(d,-1,dateadd(yy,1,@FromDate)) then isnull(Bud,0) else 0 end)) end C
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(Bud,0) else 0 end)) end D
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,Sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Actual,0) else 0 end)) end E
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,Sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Actual,0) else 0 end)-sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Bud,0) else 0 end)) end F
,case when len(tv.R1C1)>0 then '' else convert(nvarchar,case when sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Bud,0) else 0 end) between -1 and 1 then 0 else (Sum(case When tp [Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Actual,0) else 0 end)/sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(tp.Bud,0) else 0 end)*100) end) end G
,case when len(tv.R1C1)>0 then '=subtotal(9,' + tv.r1c1 + ')' else convert(nvarchar,Sum(case When tp.[Date] between dateadd(yy,0,@FromDate) and dateadd(yy,0,@YTD) then isnull(Rev,0) -- Rev er her rettet fra REv til Faktisk else 0 end +case When tp.[Date] between dateadd(d,1,@YTD) and dateadd(d,-1,dateadd(yy,1,@FromDate)) then isnull(tp.Rev,0) else 0 end)) end H
I know it looks huge and maybe it is stupid of me to show it this way, but after 2 weeks of tries and not so much success people started to push me and complain that I am using to much time on this... and I honestly dont really know what to do more.
Up until now I have used the SQL Profiler tool in order to take a file with the workload and use it in the Tunning Advisor tool to see what recommandations it makes. And I got some recomandations which said to build some statistics and some indexes, which I did, but the difference was almost unnoticeable. Another thing which i think is a good idea to mention is that when calculating(before using the Profiler and Tunning Advisor) the estimated number of rows which this part of the stored procedure should return is 1600, while the actual number of rows is 536. As far as I've read that is not a good thing. Now the wierd part comes, that after using the advice got from the Tunning Advisor, instead of decresing the estimated nr of row, it got increased to 2800, but the speed was pretty much the same 2-3sec. I know that there are a lot of more things which can be done, but i dont not posses either the knowledge or the time to dig in into them at the moment, so if anyone could point me in the right direction that would be great. If there is anything else I could provide in order to get to the bottom of this, I will glady do so, so please just ask. And I almost forgot, the expected result would be probably 1sec or less.. due to the fact that it is only 536 rows, and my clients have seen queries which perform much faster on over 20.000 rows