Execution of sql query takes a long time - sql

I have this problem with my query that it is really slow. I am using MSSQL server 2008 and have 3 DB with hundreds of sample data in it. The query will return a name and value and a computed percentage based on the 3 DBs. But the query I have will take almost 10mins to execute which is really a long time to take. I am still learning SQL and still not that good so I think the query I have is not using the best practice and not organized. Can anybody point to me where or how I can improve my query to run faster?
SELECT data.Ret,
case
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') and (data.rowid % 50) = 0 then (data.rowid / 50)-1
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') then (data.rowid / 50)
else 0 end as batchStore
,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal,data.Version
,data.A_Percent,data.T_Percent,data.F_Percent
from
(
SELECT report.Ret,
CASE when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5')
then row_number() over (PARTITION BY report.Ret,report.Version order by report.Ret, report.MajorName)
else 0 end as rowid
,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal,report.Version
,report.GTotal_A,report.GTotal_T,report.GTotal_F
,ISNULL(sum(report.Abn) / NULLIF(cast(report.GTotal_A as decimal),0),0) * 100 as A_Percent
,ISNULL(sum(report.Trn) / NULLIF(cast(report.GTotal_T as decimal),0),0) * 100 as T_Percent
,ISNULL(sum(report.Fld)/ NULLIF(cast(report.GTotal_F as decimal),0) * 100,0) as F_Percent
From
(
Select
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MajorName,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MinorName,
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MajorVal,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MinorVal,
csl.Cust_Name as Ret,l.SWVersion as Version
,d.Abn,d.Trn,d.Fld,data.GTotal_A ,data.GTotal_T,data.GTotal_F
From db_mon.dbo.CustSL csl
join db_tax.dbo.vwLane l
on (l.externalid = csl.custsl_id)
join db_mon.dbo.DaySummary dy
on (dy.Str = csl.s_name and dy.Lne = csl.l_name and year(dy.day_stamp) = year(#time_start_date) and year(dy.day_stamp) =year(#time_end_date))
Left Outer Join
(
Select a.id As AttributeId, a.attribute_name As AttributeName,
(Case When a.attribute_value_type = 'string' Then ea.string_value
Else (Case When a.attribute_value_type = 'integer' Then cast(ea.integer_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'date' Then cast(ea.date_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'boolean' Then cast(ea.boolean_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'entity' Then cast(ea.ref_entity_id as nvarchar(100)) Else null End)
End)
End)
End)
End) As AttributeValue,
e.id As EntityId
From db_tax.dbo.entity_type et
Inner Join db_tax.dbo.entity As e on et.id = e.entity_type_id
Inner Join db_tax.dbo.entity_attribute As ea on e.id = ea.entity_id
Inner Join db_tax.dbo.attribute As a on ea.attribute_id = a.id
WHERE et.entity_type_name in ('Sticker','Label') And
a.id = (case WHEN #attribute_id = '' then 1 else cast(#attribute_id as int) end)
) AS attrib
On attrib.EntityId = l.L_Id
inner join db_mon.dbo.DaySummary d
on (csl.Cust_Name = d.Ret and csl.s_name = d.stckr and csl.l_name = d.label and l.SWVersion = d.Version)
join (
SELECT Ret,version,sum(Abn) as GTotal_A,sum(Trn) as GTotal_T,sum(Fld) as GTotal_F
from db_mon.dbo.DaySummary
where day_stamp >= #time_start_date and day_stamp <=#time_end_date
GROUP BY Ret,version
) data
on (d.Ret = data.Ret and l.SWVersion = data.Version)
WHERE (CHARINDEX(',' + CONVERT(VARCHAR,l.S_Id) + ',','xxx,' + #entities + ',xxx')>0 OR CHARINDEX(',' + CONVERT(VARCHAR,l.L_Id) + ',','xxx,' + #entities + ',xxx')>0)
and d.day_stamp >= #time_start_date
and d.day_stamp <=#time_end_date
) As report
Group By report.Ret,report.Version,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal
,report.GTotal_A,report.GTotal_T,report.GTotal_F
)data
order By data.Ret,data.Version,batchStore,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal
Does using a lot of join causes the slow execution?

SUB Select queries will always be slower then proper joins.
You are running 3 sub selects deep. This is going to impact your performance regardless of changing indexes etc.
You need to rewrite the whole thing to stop using sub selects.

Related

SQL: LEFT OUTER JOIN not returning any rows

I have a query that is using a LEFT OUTER JOIN to merge 2 data sets. I know both data sets should return data because I ran the superquery and the subquery separately. For some reason, the query is returning zero results. Anyone know why?
Left data:
item FG_lots
447845 E2211
Right data:
candy_lot_check candy_item
L2211 835116
Intended result:
item FG_lots candy_lot_check candy_item
447845 E2211 null null
The result from my broken query (no results):
item FG_lots candy_lot_check candy_item
The query:
--Initialization--
DECLARE #Item NVARCHAR(30) = '447845'
DECLARE #Date datetime = '6/13/2016'
SET DATEFIRST 1;
DECLARE #client NVARCHAR(20)
SET #client = (SELECT i.Uf_ClientName FROM item AS i WHERE i.item = #Item)
DECLARE #count integer
--Query--
SET #count = (CASE
WHEN (#client = 'A' OR #client = 'B')
THEN 4
WHEN #client = 'C'
THEN 3
WHEN #client = 'D'
THEN 5
ELSE
4
END)
SELECT DISTINCT
t.item,
LEFT(t.lot,#count) AS FG_lots,
(CASE
WHEN candylot.candy_lots IS NULL
THEN 'NO MATCH'
ELSE candylot.candy_lots
END) AS candy_lot_check,
(CASE
WHEN candylot.item IS NULL
THEN 'NO MATCH'
ELSE candylot.item
END) AS candy_item
FROM
ISW_LPTrans AS t
LEFT OUTER JOIN
(
SELECT
t.item,
LEFT(t.lot,#count) AS candy_lots,
t.ref_num AS job,
t.ref_line_suf AS suffix
FROM
ISW_LPTrans AS t
INNER JOIN item AS i on i.item = t.item
WHERE
i.product_code = 'RM-Candy' AND
t.trans_date = #Date AND
t.trans_type = 'I' AND
t.ref_num IN
(
SELECT TOP 1
j.job
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
ORDER BY
j.job
)
AND t.ref_line_suf IN
(
SELECT TOP 1
j.suffix
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
)
GROUP BY
t.item,
t.lot,
t.ref_num,
t.ref_line_suf
) AS candylot ON LEFT(t.lot, #count) = candylot.candy_lots
WHERE
t.ref_num = candylot.job AND
t.ref_line_suf = candylot.suffix AND
t.trans_type = 'F' AND
t.item = #Item AND
t.trans_date = #Date
You've got two 't' aliases, try altering it.
It seems you could rewrite it to make it more readable (joinwise, not indentwise), it could be that something's not right in the logic as well

SQL CASE wrong output

I have this weird encounter using CASE in sql 2014.
This is my query:
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE dbo.GetFunctionAge(C.Birthdate)
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
this is the output:
Here is the GetFunctionAge function if you might ask.
IF EXISTS (
SELECT *
FROM dbo.sysobjects
WHERE ID = OBJECT_ID(N'[dbo].[GetFunctionAge]') AND
xtype in (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[GetFunctionAge]
GO
CREATE FUNCTION [dbo].[GetFunctionAge](#BirthDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
IF(#BirthDate = '1753-01-01 00:00:00.000')
BEGIN
SET #Age = 0
END
ELSE
BEGIN
SET #Age = DATEDIFF(hour,#BirthDate,GETDATE())/8766
END
RETURN #Age
END
GO
Question:
Why is Column Age in my output is 0which should be ''?
I added (No column name) to show that its output is 0 so my expected output base from my case condition is '' not 0
I didn't receive any error regarding inconsistency of data so why is case behaving like that?
Thanks for those who could clarify this to me.
SELECT
(CASE
WHEN a.ageint = 0 THEN ''
ELSE cast(a.ageint as varchar(3))
END) AS Age
, a.ageint
, c.Birthdate
FROM Client as C
CROSS APPLY (
SELECT
ISNULL(dbo.GetFunctionAge(C.Birthdate), 0) AS ageint
) AS a
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
;
You can cast it into varchar so you can return ' '.
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE Cast(dbo.GetFunctionAge(C.Birthdate) as varchar(5))
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
But If you wish to remain your Age column in data type int.
You could just use NULL instead of ' '

SQL Conversion failed when converting row number

So I've been trying to add an Dynamic Row Number column with out using Dynamic SQL. However when I try I get an error 'Conversion failed when converting character string to smalldatetime data type.'
I Know the Error is coming from in the functions So if you want to just look at the switch case in the function that is the problem, but here is the stored procedure just in case you need to see it.
I have a store procedure which looks like this:
ALTER PROCEDURE [dbo].[MMS_EdgateMainQueue]
-- Add the parameters for the stored procedure here
#OrderByColumnID int = 3,
#Skip int = 0,
#Take int = 0,
#Descending bit = 1,
#ResultCount INT OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #UrlTitlePrefix varchar(2080) = '<a href="/Title/PageByExtTitleID?ActionName=Edgate&ExtTitleID='
Declare #UrlProducerPrefix varchar(2080) = '<a href="/Producers/ByExtVendorID?ActionName=Details&ExtVendorID='
Declare #Urlmidfix varchar(100) = '">'
Declare #UrlPostFix varchar(100) = '</a>'
SELECT TOP (#Take)
[row_numb],
#UrlTitlePrefix + ExtTitleID + #Urlmidfix + ExtTitleID + #UrlPostFix as [Item #],
f.Title as Name,
#UrlProducerPrefix + f.ExtVendorID + #Urlmidfix + f.DisplayName + #UrlPostFix as Producer,
f.Created as Created,
isnull(f.Academic, '') as Academic,
isnull(f.Sears,'') as Sears,
isnull(f.Editor, '') as Editor,
CONVERT(INT, f.[Copy]) AS Copy,
f.[Segment],
CONVERT(INT, f.[Taxonomy]) AS Taxonomy,
f.[Priority]
FROM EdgateNewTitlesInnerQuery(#OrderByColumnID, #Descending) as f
Where f.[row_numb] Between ((#Skip * #Take) + 1) and ((#Skip + 1) * #Take) order by f.[row_numb]
END
And The Inner Function Looks Like:
ALTER FUNCTION [dbo].[EdgateNewTitlesInnerQuery]
(
#OrderByColumnID int,
#Descending bit
)
RETURNS TABLE
AS
RETURN
(
SELECT DISTINCT
v.ExtVendorID,
t.ID,
t.ExtTitleID,
t.Title,
v.DisplayName,
t.Created,
ecs.Title as [Academic],
ssub.Title as [Sears],
etw.EditorName as [Editor],
etw.CopyDone AS [Copy],
etw.SegmentsStatus as [Segment],
etw.TaxonomyDone AS [Taxonomy],
CASE WHEN wft.[Priority] is null THEN 0 ELSE wft.[Priority] END as [Priority],
--row_number() OVER (ORDER BY t.Created DESC) AS [row_number]
row_number() OVER (ORDER BY
CASE #OrderByColumnID WHEN 0 THEN t.ExtTitleID
WHEN 1 THEN t.Title
WHEN 2 THEN v.DisplayName
WHEN 3 THEN t.Created
WHEN 4 THEN ecs.Title
WHEN 5 THEN ssub.Title
WHEN 6 THEN etw.EditorName
WHEN 7 THEN etw.CopyDone
WHEN 8 THEN etw.SegmentsStatus
WHEN 9 THEN etw.TaxonomyDone
WHEN 10 THEN CASE WHEN wft.[Priority] is null THEN 0 ELSE wft.[Priority] END
ELSE t.Created
END DESC ) AS [row_numb]
FROM [Title] t
join EdgateTitleWorkflow etw on etw.FK_TitleID = t.ID
join Vendor v on v.ExtVendorID = t.ProducerID
join CollectionItem i on i.TitleID = t.ID and i.CollectionID = 16
left join [EdgateSuggestedAcademicSubject] esas on esas.FK_TitleID = t.ID and esas.isPrimary = 1
left join EC_Subject ecs on ecs.ID = esas.FK_SubjectID
left join [FMGSuggestedSears] fss on fss.FK_TitleID = t.ID and fss.isPrimary = 1
left join [FMGSearsSubjects] ssub on ssub.ID = fss.SearsSubjectID and ssub.ParentID is null
left join [WorkFlow_Tracker] wft on wft.TitleID = t.ID
where (etw.CopyDone = 0 or etw.TaxonomyDone = 0 or etw.SegmentsStatus = 0)
)
I've tried passing this in as a string originally but it just didn't sort at all. So I was looking at similar problems and tried this solution Here
but my switch Case is now throwing a Conversion Error. Does anyone have an Idea on how to fix this?
The problem is that case is an expression that returns one type, defined during compilation. You can fix this with a separate case for each key. I think this is the statement you want:
row_number() OVER (ORDER BY (CASE WHEN #OrderByColumnID = 0 THEN t.ExtTitleID END),
(CASE WHEN #OrderByColumnID = 1 THEN t.Title END),
(CASE WHEN #OrderByColumnID = 2 THEN v.DisplayName END),
(CASE WHEN #OrderByColumnID = 3 THEN t.Created END),
(CASE WHEN #OrderByColumnID = 4 THEN ecs.Title END),
(CASE WHEN #OrderByColumnID = 5 THEN ssub.Title END),
(CASE WHEN #OrderByColumnID = 6 THEN etw.EditorName END),
(CASE WHEN #OrderByColumnID = 7 THEN etw.CopyDone END),
(CASE WHEN #OrderByColumnID = 8 THEN etw.SegmentsStatus END),
(CASE WHEN #OrderByColumnID = 9 THEN etw.TaxonomyDone END),
(CASE WHEN #OrderByColumnID = 10 THEN COALESCE(wft.[Priority], 0) END)
t.Created DESC
)

SQL Server processing for jquery datatables order by issue?

I have written the following script to mimic the incoming parameters from datatables and try to filter the results using the parameters. Everything works fine except the order by clause. Basically it only orders by rownumber and does not take into consideration the case statement which provides the second order by column.
declare #sSortColumn as nvarchar(50)='Country';
declare #sSortDirection as nvarchar(5) = 'Desc';
declare #sSearch as nvarchar(50) = '';
declare #iDisplayLength as int = 20;
declare #iDisplayStart as int = 20;
declare #sIDsearch as int = CASE WHEN ISNUMERIC(#sSearch) = 1 THEN CAST(#sSearch AS INT) ELSE 0 END;
WITH media AS
(
select ROW_NUMBER() OVER (ORDER BY mc.id) as RowNumber,
mc.id,mc.Name, mc.CityID,lc.Name as Country
from Lookup_MediaChannels mc
left join Lookup_SonarMediaTypes st on mc.SonarMediaTypeID = st.ID
left join Lookup_SonarMediaGroups sg on sg.ID = st.SonarMediaGroupID
left join Lookup_MediaTypes mt on mc.MediaTypeID = mt.ID
left join Lookup_SonarMediaGroups sg1 on sg1.ID = mt.MediaGroupID
left join lookup_Countries lc on lc.id = mc.countryid
where mc.Name like '%'+#sSearch+'%'
and (sg1.ID=1 or sg.ID =1 )
or mc.id = #sIDsearch
)
SELECT RowNumber, Name, Country
FROM media
WHERE RowNumber BETWEEN (#iDisplayStart+ 1) AND (#iDisplayStart+ #iDisplayLength)
order by rownumber,
CASE WHEN #sSortColumn = 'Name' AND #sSortDirection = 'Desc'
THEN Name END DESC,
CASE WHEN #sSortColumn = 'Name' AND #sSortDirection != 'Desc'
THEN Name END,
CASE WHEN #sSortColumn = 'Country' AND #sSortDirection = 'Desc'
THEN Country END DESC,
CASE WHEN #sSortColumn = 'Country' AND #sSortDirection != 'Desc'
THEN Country END
This simplified example may help you
http://sqlfiddle.com/#!6/35ffb/10
Set up some dummy data (this would be replaced by your select statement)
create table x(
id int,
name varchar(3),
country varchar(2)
)
insert into x
values (1,'aaa','uk'),
(2,'aaa','us'),
(3,'baa','uk'),
(4,'caa','uk'),
(5,'baa','it')
Some vars to hold sort field and sort order
declare #so char(1)
declare #sf char(1)
set #so = 'a' -- a = asc d = desc
set #sf = 'n' -- n = name c = country
and a select to return sorted data
SELECT row_number()
OVER (order by
CASE WHEN #so = 'd' THEN sf END desc,
CASE WHEN #so <> 'd' THEN sf end,
id
) AS aa, name,country
FROM (
SELECT x.*, case #sf when 'n' then name when 'c' then country end sf
FROM X
) X

Splitting SQL query with many joins into smaller ones helps?

We need to do some reporting every night on our SQL server 2008R2. Calculating the reports takes several hours. In order to shorten the time we precalculate a table. This table is created based on JOINining 12 quite big (tens of milions row) tables.
The calculation of this aggregation table took until few days ago cca 4 hours. Our DBA than split this big join into 3 smaller joins (each joining 4 tables). The temporar result is everytime saved into a temporary table, which is used in the next join.
The result of the DBA enhancment is, that the aggregation table is calculated in 15 minutes. I wondered how is that possible. DBA told me that it is because the number of data the server must process is smaller. In other words, that in the big original join the server has to work with more data than in summed smaller joins. However, I would presume that optimizer would take care of doing it effeciently with the original big join, splitting the joins on its own and sending only the number of columns needed to next joins.
The other thing he has done is that he created an index on one of the tmeporary tables. However, once again I would think that the optimizer will create the appropriate hash tables if needed and alltogether better optimize the computation.
I talked about this with our DBA, but he was himself uncertain about what cased the improvement in processing time. He just mentioned, that he would not blame the server as it can be overwhelming to compute such big data and that it is possible that the optimizer has hard time to predict the best execution plan ... . This I understand, but I would like to have more defining answer as to exactly why.
So, the questions are:
1. "What could possibly cause the big improvement?"
2. "Is it a standard procedure to split big joins into smaller?"
3. "Is the amount of data which srever has to process really smaller in case of multiple smaller joins?"
Here is the original query:
Insert Into FinalResult_Base
SELECT
TC.TestCampaignContainerId,
TC.CategoryId As TestCampaignCategoryId,
TC.Grade,
TC.TestCampaignId,
T.TestSetId
,TL.TestId
,TSK.CategoryId
,TT.[TestletId]
,TL.SectionNo
,TL.Difficulty
,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty)
,TQ.[QuestionId]
,TS.StudentId
,TS.ClassId
,RA.SubjectId
,TQ.[QuestionPoints]
,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0
When TQ.[QuestionPoints] > 0 Then 1
Else 0 End
,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1
When TQ.[QuestionPoints] Is null Then 1
Else 0 End
,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End
,TS.Redizo
,TT.ViewCount
,TT.SpentTime
,TQ.[Position]
,RA.SpecialNeeds
,[Version] = 1
,TestAdaptationId = TA.Id
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,QuestionRate = Q.Rate
,TestQuestionId = TQ.Guid
,AnswerType = TT.TestletAnswerTypeId
FROM
[TestQuestion] TQ WITH (NOLOCK)
Join [TestTask] TT WITH (NOLOCK) On TT.Guid = TQ.TestTaskId
Join [Question] Q WITH (NOLOCK) On TQ.QuestionId = Q.QuestionId
Join [Testlet] TL WITH (NOLOCK) On TT.TestletId = TL.Guid
Join [Test] T WITH (NOLOCK) On TL.TestId = T.Guid
Join [TestSet] TS WITH (NOLOCK) On T.TestSetId = TS.Guid
Join [RoleAssignment] RA WITH (NOLOCK) On TS.StudentId = RA.PersonId And RA.RoleId = 1
Join [Task] TSK WITH (NOLOCK) On TSK.TaskId = TT.TaskId
Join [Category] C WITH (NOLOCK) On C.CategoryId = TSK.CategoryId
Join [TimeWindow] TW WITH (NOLOCK) On TW.Id = TS.TimeWindowId
Join [TestAdaptation] TA WITH (NOLOCK) On TA.Id = TW.TestAdaptationId
Join [TestCampaign] TC WITH (NOLOCK) On TC.TestCampaignId = TA.TestCampaignId
WHERE
T.TestTypeId = 1 -- eliminuji ankety
And t.ProcessedOn is not null -- ne vsechny, jen dokoncene
And TL.ShownOn is not null
And TS.Redizo not in (999999999, 111111119)
END;
The new splitted joins after DBA great work:
SELECT
TC.TestCampaignContainerId,
TC.CategoryId As TestCampaignCategoryId,
TC.Grade,
TC.TestCampaignId,
T.TestSetId
,TL.TestId
,TL.SectionNo
,TL.Difficulty
,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty) -- prevod na A5, B4, B5 ...
,TS.StudentId
,TS.ClassId
,TS.Redizo
,[Version] = 1 -- ?
,TestAdaptationId = TA.Id
,TL.Guid AS TLGuid
,TS.TimeWindowId
INTO
[#FinalResult_Base_1]
FROM
[TestSet] [TS] WITH (NOLOCK)
JOIN [Test] [T] WITH (NOLOCK)
ON [T].[TestSetId] = [TS].[Guid] AND [TS].[Redizo] NOT IN (999999999, 111111119) AND [T].[TestTypeId] = 1 AND [T].[ProcessedOn] IS NOT NULL
JOIN [Testlet] [TL] WITH (NOLOCK)
ON [TL].[TestId] = [T].[Guid] AND [TL].[ShownOn] IS NOT NULL
JOIN [TimeWindow] [TW] WITH (NOLOCK)
ON [TW].[Id] = [TS].[TimeWindowId] AND [TW].[IsActive] = 1
JOIN [TestAdaptation] [TA] WITH (NOLOCK)
ON [TA].[Id] = [TW].[TestAdaptationId] AND [TA].[IsActive] = 1
JOIN [TestCampaign] [TC] WITH (NOLOCK)
ON [TC].[TestCampaignId] = [TA].[TestCampaignId] AND [TC].[IsActive] = 1
JOIN [TestCampaignContainer] [TCC] WITH (NOLOCK)
ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1
;
SELECT
FR1.TestCampaignContainerId,
FR1.TestCampaignCategoryId,
FR1.Grade,
FR1.TestCampaignId,
FR1.TestSetId
,FR1.TestId
,TSK.CategoryId AS [TaskCategoryId]
,TT.[TestletId]
,FR1.SectionNo
,FR1.Difficulty
,TestletName = Char(65+FR1.SectionNo) + CONVERT(varchar(4),6 - FR1.Difficulty) -- prevod na A5, B4, B5 ...
,FR1.StudentId
,FR1.ClassId
,FR1.Redizo
,TT.ViewCount
,TT.SpentTime
,[Version] = 1 -- ?
,FR1.TestAdaptationId
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,AnswerType = TT.TestletAnswerTypeId
,TT.Guid AS TTGuid
INTO
[#FinalResult_Base_2]
FROM
#FinalResult_Base_1 FR1
JOIN [TestTask] [TT] WITH (NOLOCK)
ON [TT].[TestletId] = [FR1].[TLGuid]
JOIN [Task] [TSK] WITH (NOLOCK)
ON [TSK].[TaskId] = [TT].[TaskId] AND [TSK].[IsActive] = 1
JOIN [Category] [C] WITH (NOLOCK)
ON [C].[CategoryId] = [TSK].[CategoryId]AND [C].[IsActive] = 1
;
DROP TABLE [#FinalResult_Base_1]
CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class]
ON [dbo].[#FinalResult_Base_2] ([StudentId],[ClassId])
INCLUDE ([TTGuid])
SELECT
FR2.TestCampaignContainerId,
FR2.TestCampaignCategoryId,
FR2.Grade,
FR2.TestCampaignId,
FR2.TestSetId
,FR2.TestId
,FR2.[TaskCategoryId]
,FR2.[TestletId]
,FR2.SectionNo
,FR2.Difficulty
,FR2.TestletName
,TQ.[QuestionId]
,FR2.StudentId
,FR2.ClassId
,RA.SubjectId
,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer
,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0
When TQ.[QuestionPoints] > 0 Then 1 -- cookie
Else 0 End
,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1
When TQ.[QuestionPoints] Is null Then 1
Else 0 End
,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End
,FR2.Redizo
,FR2.ViewCount
,FR2.SpentTime
,TQ.[Position] AS [QuestionPosition]
,RA.SpecialNeeds -- identifikace SVP
,[Version] = 1 -- ?
,FR2.TestAdaptationId
,FR2.TaskId
,FR2.TaskPosition
,QuestionRate = Q.Rate
,TestQuestionId = TQ.Guid
,FR2.AnswerType
INTO
[#FinalResult_Base]
FROM
[#FinalResult_Base_2] FR2
JOIN [TestQuestion] [TQ] WITH (NOLOCK)
ON [TQ].[TestTaskId] = [FR2].[TTGuid]
JOIN [Question] [Q] WITH (NOLOCK)
ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1
JOIN [RoleAssignment] [RA] WITH (NOLOCK)
ON [RA].[PersonId] = [FR2].[StudentId]
AND [RA].[ClassId] = [FR2].[ClassId] AND [RA].[IsActive] = 1 AND [RA].[RoleId] = 1
drop table #FinalResult_Base_2;
truncate table [dbo].[FinalResult_Base];
insert into [dbo].[FinalResult_Base] select * from #FinalResult_Base;
drop table #FinalResult_Base;
For the first, please, rebuilding indexes on your tables by this script (this may take a long time) -
SET NOCOUNT ON;
DECLARE
#SQL NVARCHAR(MAX)
, #IndexName SYSNAME
, #Output VARCHAR(200)
, #ServerVersion VARCHAR(100)
SELECT #ServerVersion = CAST(SERVERPROPERTY('Edition') AS VARCHAR(100))
DECLARE cur CURSOR LOCAL READ_ONLY FORWARD_ONLY FOR
SELECT
'ALTER INDEX [' + ix.name + N'] ON [' + SCHEMA_NAME(t.[schema_id]) + '].[' + t.name + '] ' +
CASE
WHEN ps.avg_fragmentation_in_percent > 50 THEN
CASE WHEN #ServerVersion LIKE 'Enterprise%' OR #ServerVersion LIKE 'Developer%' THEN
'REBUILD WITH (SORT_IN_TEMPDB = ON, ONLINE = ON ' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') '
ELSE
'REBUILD WITH (SORT_IN_TEMPDB = ON' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') '
END
ELSE 'REORGANIZE '
END +
CASE
WHEN ps.partition_number > 1 THEN N' PARTITION = ' + CAST(ps.partition_number AS NVARCHAR(MAX))
ELSE N''
END + ';', ix.name
FROM sys.indexes ix
JOIN sys.objects t ON t.[object_id] = ix.[object_id]
JOIN (
SELECT
[object_id]
, index_id
, avg_fragmentation_in_percent
, partition_number
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, N'LIMITED')
WHERE page_count > 100
AND avg_fragmentation_in_percent > 10
) ps ON t.[object_id] = ps.[object_id] AND ix.index_id = ps.index_id
WHERE t.[type] = 'U'
AND t.name IN (
'TestQuestion', 'TestTask', 'Question', 'Testlet',
'Test', 'TestSet', 'RoleAssignment', 'Task',
'category', 'TimeWindow', 'TestAdaptation', 'TestCampaign')
OPEN cur
FETCH NEXT FROM cur INTO #SQL, #IndexName
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #Output = CONVERT(NVARCHAR(15), GETDATE(), 114) + ': ' + #IndexName
RAISERROR(#Output, 0, 1) WITH NOWAIT
EXEC sys.sp_executesql #SQL
FETCH NEXT FROM cur INTO #SQL, #IndexName
END
CLOSE cur
DEALLOCATE cur
And after it try this query -
INSERT INTO dbo.FinalResult_Base
SELECT
TC.TestCampaignContainerId
, TestCampaignCategoryId = TC.CategoryID
, TC.Grade
, TC.TestCampaignId
, T.TestSetId
, TL.TestId
, TSK.CategoryID
, TT.[TestletId]
, TL.SectionNo
, TL.Difficulty
, TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty)
, TQ.[QuestionId]
, TS.StudentId
, TS.ClassId
, RA.SubjectId
, TQ.[QuestionPoints]
, GoodAnswer =
CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0
THEN 1
ELSE 0
END
, WrongAnswer =
CASE
WHEN ISNULL(TQ.[QuestionPoints], 0) = 0
THEN 1
ELSE 0
END
, NoAnswer =
CASE WHEN TQ.[QuestionPoints] IS NULL
THEN 1
ELSE 0
END
, TS.Redizo
, TT.ViewCount
, TT.SpentTime
, TQ.[Position]
, RA.SpecialNeeds
, [Version] = 1
, TestAdaptationId = TA.id
, TaskId = TSK.TaskId
, TaskPosition = TT.Position
, QuestionRate = Q.Rate
, TestQuestionId = TQ.guid
, AnswerType = TT.TestletAnswerTypeId
FROM dbo.TestQuestion TQ WITH (NOLOCK)
JOIN dbo.TestTask TT WITH (NOLOCK) ON TT.[guid] = TQ.TestTaskId
JOIN dbo.Question Q WITH (NOLOCK) ON TQ.QuestionId = Q.QuestionId
JOIN (
SELECT *
FROM dbo.Testlet TL WITH (NOLOCK)
WHERE TL.ShownOn IS NOT NULL
) TL ON TT.TestletId = TL.[guid]
JOIN (
SELECT *
FROM dbo.Test T WITH (NOLOCK)
WHERE T.TestTypeId = 1
AND T.ProcessedOn IS NOT NULL
) T ON TL.TestId = T.[guid]
JOIN (
SELECT *
FROM dbo.TestSet TS WITH (NOLOCK)
WHERE TS.Redizo NOT IN (999999999, 111111119)
) TS ON T.TestSetId = TS.[guid]
JOIN dbo.RoleAssignment RA WITH (NOLOCK) ON TS.StudentId = RA.PersonID AND RA.RoleId = 1
JOIN dbo.Task TSK WITH (NOLOCK) ON TSK.TaskId = TT.TaskId
JOIN dbo.category C WITH (NOLOCK) ON C.CategoryID = TSK.CategoryID
JOIN dbo.TimeWindow TW WITH (NOLOCK) ON TW.id = TS.TimeWindowId
JOIN dbo.TestAdaptation TA WITH (NOLOCK) ON TA.id = TW.TestAdaptationId
JOIN dbo.TestCampaign TC WITH (NOLOCK) ON TC.TestCampaignId = TA.TestCampaignId
And try this query -
SELECT TC.TestCampaignContainerId
,TC.CategoryID AS TestCampaignCategoryId
,TC.Grade
,TC.TestCampaignId
,T.TestSetId
,TL.TestId
,TL.SectionNo
,TL.Difficulty
,TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty) -- prevod na A5, B4, B5 ...
,TS.StudentId
,TS.ClassId
,TS.Redizo
,[Version] = 1 -- ?
,TestAdaptationId = TA.id
,TL.guid AS TLGuid
,TS.TimeWindowId
INTO [#FinalResult_Base_1]
FROM (
SELECT *
FROM dbo.[TestSet] [TS] WITH (NOLOCK)
WHERE [TS].[Redizo] NOT IN (999999999, 111111119)
) TS
JOIN (
SELECT *
FROM dbo.[Test] [T] WITH (NOLOCK)
WHERE [T].[TestTypeId] = 1
AND [T].[ProcessedOn] IS NOT NULL
) T ON [T].[TestSetId] = [TS].[guid]
JOIN (
SELECT *
FROM dbo.[Testlet] [TL] WITH (NOLOCK)
WHERE [TL].[ShownOn] IS NOT NULL
) TL ON [TL].[TestId] = [T].[guid]
JOIN (
SELECT *
FROM dbo.[TimeWindow] [TW] WITH (NOLOCK)
WHERE [TW].[IsActive] = 1
) TW ON [TW].[id] = [TS].[TimeWindowId]
JOIN (
SELECT *
FROM dbo.[TestAdaptation] [TA] WITH (NOLOCK)
WHERE [TA].[IsActive] = 1
) TA ON [TA].[id] = [TW].[TestAdaptationId]
JOIN (
SELECT *
FROM dbo.[TestCampaign] [TC] WITH (NOLOCK)
WHERE [TC].[IsActive] = 1
) TC ON [TC].[TestCampaignId] = [TA].[TestCampaignId]
--possible unused join in this query
--JOIN dbo.[TestCampaignContainer] [TCC] WITH (NOLOCK) ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1
SELECT FR1.TestCampaignContainerId
,FR1.TestCampaignCategoryId
,FR1.Grade
,FR1.TestCampaignId
,FR1.TestSetId
,FR1.TestId
,TSK.CategoryID AS [TaskCategoryId]
,TT.[TestletId]
,FR1.SectionNo
,FR1.Difficulty
,TestletName = CHAR(65 + FR1.SectionNo) + CONVERT(VARCHAR(4), 6 - FR1.Difficulty) -- prevod na A5, B4, B5 ...
,FR1.StudentId
,FR1.ClassId
,FR1.Redizo
,TT.ViewCount
,TT.SpentTime
,[Version] = 1 -- ?
,FR1.TestAdaptationId
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,AnswerType = TT.TestletAnswerTypeId
,TT.guid AS TTGuid
INTO [#FinalResult_Base_2]
FROM #FinalResult_Base_1 FR1
JOIN [TestTask] [TT] WITH (NOLOCK) ON [TT].[TestletId] = [FR1].[TLGuid]
JOIN [Task] [TSK] WITH (NOLOCK) ON [TSK].[TaskId] = [TT].[TaskId]
--possible unused join
--JOIN [category] [C] WITH (NOLOCK) ON [C].[CategoryID] = [TSK].[CategoryID]
WHERE [TSK].[IsActive] = 1
--AND [C].[IsActive] = 1
DROP TABLE [#FinalResult_Base_1]
CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class]
ON [dbo].[#FinalResult_Base_2] ([StudentId], [ClassId])
INCLUDE ([TTGuid])
TRUNCATE TABLE [dbo].[FinalResult_Base];
INSERT INTO [dbo].[FinalResult_Base]
SELECT FR2.TestCampaignContainerId
,FR2.TestCampaignCategoryId
,FR2.Grade
,FR2.TestCampaignId
,FR2.TestSetId
,FR2.TestId
,FR2.[TaskCategoryId]
,FR2.[TestletId]
,FR2.SectionNo
,FR2.Difficulty
,FR2.TestletName
,TQ.[QuestionId]
,FR2.StudentId
,FR2.ClassId
,RA.SubjectId
,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer
, GoodAnswer =
CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0
THEN 1
ELSE 0
END
, WrongAnswer =
CASE
WHEN ISNULL(TQ.[QuestionPoints], 0) = 0
THEN 1
ELSE 0
END
, NoAnswer =
CASE WHEN TQ.[QuestionPoints] IS NULL
THEN 1
ELSE 0
END
,FR2.Redizo
,FR2.ViewCount
,FR2.SpentTime
,TQ.[Position] AS [QuestionPosition]
,RA.SpecialNeeds -- identifikace SVP
,[Version] = 1 -- ?
,FR2.TestAdaptationId
,FR2.TaskId
,FR2.TaskPosition
,QuestionRate = Q.Rate
,TestQuestionId = TQ.guid
,FR2.AnswerType
FROM [#FinalResult_Base_2] FR2
JOIN [TestQuestion] [TQ] WITH (NOLOCK) ON [TQ].[TestTaskId] = [FR2].[TTGuid]
JOIN [Question] [Q] WITH (NOLOCK) ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1
JOIN [RoleAssignment] [RA] WITH (NOLOCK) ON [RA].[PersonID] = [FR2].[StudentId]
AND [RA].[ClassId] = [FR2].[ClassId]
AND [RA].[IsActive] = 1
AND [RA].[RoleId] = 1
DROP TABLE #FinalResult_Base_2;
IMHO It should not be the case, I faced similar problem and took the following steps to optimize it.
Try putting Indexes on the columns which are used in filtering (The
columns deciding the joins).
Try to put indexes on Views, It could be done but It needs some
special requirements.
Have some jobs for Index Rebuilding.
Use another mirror instance of DB for reporting leave the live DB
Don't use functions while joining if you want to transform data do it
after joining.
Use Query optimizer to view what part of join is taking most of the
time/resources.
Use an Archive table to purge data into it from live DB.
Hope it helps :)