SQLTimeout when executing stored procedure in SQL Server 2012 - sql

I'm getting an error:
System.Data.SqlClient.SqlException: Timeout expired
with a stored procedure when the result set is above a certain record count. Unfortunately this error is only occurring in a production environment which I have very limited access to.
This is a legacy application and I didn't build this stored procedure, so I have to be careful about changes altering it's expected (but undocumented) behavior. I have a .NET background, but limited SQL Server experience.
The highest number of records that could be returned is 5000 (this is how many records are currently in the db). I don't know the exact threshold where it starts to fail, but it's somewhere between 2500 and the maximum 5000 records.
The stored procedure in question consists only of two SELECT statements unioned together. Using SQL Server Profiler on my dev machine didn't reveal anything useful. Is there anything obviously wrong with this stored procedure that would cause it to exceed the 30 second timeout?
SELECT
tblRed.PhaseID, tblRed.EventID, tblRed.RMUserID, tblRed.BackupRMUserID,
tblRed.AuthorUserID, tblRed.StageID, tblRed.Status,
tblRed.PublicationDateActual, tblGreen.SystemName, tblGreen.StakeholderDisplayName,
tblGreen.StakeholderQueue, tblRed.EventTypeID,
tblRed.StageReceivedDate, tblRed.StageDueDate, tblRed.SubmitDate, tblBlue.Name,
tblBlue.Email, tblBlue.PhoneNumber, tblBrown.EventName,
MIN(tblCharm.CommunicationMaterialTypeName) AS CommunicationMaterialTypeName,
MIN(tblUp.AttachmentID) AS AttachmentID,
tblOld.SmartFormID, tblOld.isGenerated,
MIN(tblStrange.SupportDocumentTypeID) AS SupportDocumentTypeName
FROM
tblDude
INNER JOIN
tblDown ON tblDude.TeamID = tblDown.TeamID
INNER JOIN
tblGrey ON tblGrey.DepartmentID = tblDown.DepartmentID
LEFT OUTER JOIN
tblOrange ON tblOrange.DepartmentID = tblGrey.DepartmentID
LEFT OUTER JOIN
tblPurple ON tblPurple.TeamID = tblDown.TeamID
LEFT OUTER JOIN
tblPaper ON tblGrey.DivisionID = tblPaper.DivisionID
LEFT OUTER JOIN
tblNavy ON tblPaper.DivisionID = tblNavy.DivisionID
INNER JOIN
tblRed ON tblRed.PhaseID = tblDude.PhaseID
INNER JOIN
tblGreen ON tblRed.StageID = tblGreen.StageID
INNER JOIN
tblBlue ON tblBlue.UserID = tblRed.AuthorUserID
INNER JOIN
tblBrown ON tblBrown.EventID = tblRed.EventID
LEFT OUTER JOIN
tblUp ON tblUp.PhaseID = tblRed.PhaseID
LEFT OUTER JOIN
tblCharm ON tblUp.CommunicationMaterialTypeID = tblCharm.CommunicationMaterialID
AND tblUp.isLatest = 'True'
LEFT OUTER JOIN
tblOld ON tblOld.PhaseID = tblRed.PhaseID
LEFT OUTER JOIN
tblStrange ON tblStrange.PhaseID = tblRed.PhaseID
WHERE
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblDude.SMEUserID = #UserID))
OR
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblGrey.DeptSignatoryUserID = #UserID))
OR
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblPurple.DelegateUserID = #UserID))
OR
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblOrange.DelegateUserID = #UserID))
OR
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblNavy.UserID = #UserID))
OR
((tblRed.AuthorUserID <> #UserID)
AND (tblRed.Status = 'Active')
AND (tblGreen.StakeholderQueue = 'History')
AND (tblPaper.DivisionSignatoryUserID = #UserID))
GROUP BY
tblRed.PhaseID, tblRed.EventID, tblRed.RMUserID, tblRed.BackupRMUserID,
tblRed.AuthorUserID, tblRed.StageID, tblRed.Status, tblRed.PublicationDateActual,
tblGreen.SystemName, tblGreen.StakeholderDisplayName, tblGreen.StakeholderQueue,
tblRed.EventTypeID, tblRed.StageReceivedDate, tblRed.StageDueDate, tblRed.SubmitDate,
tblBlue.Name, tblBlue.Email, tblBlue.PhoneNumber, tblBrown.EventName,
tblOld.SmartFormID, tblOld.isGenerated
UNION
SELECT DISTINCT
tblRed.PhaseID, tblRed.EventID, tblRed.RMUserID, tblRed.BackupRMUserID,
tblRed.AuthorUserID, tblRed.StageID, tblRed.Status,
tblRed.PublicationDateActual, tblGreen.SystemName, tblGreen.StakeholderDisplayName,
tblGreen.StakeholderQueue, tblRed.EventTypeID,
tblRed.StageReceivedDate, tblRed.StageDueDate, tblRed.SubmitDate, tblBlue.Name,
tblBlue.Email, tblBlue.PhoneNumber, tblBrown.EventName,
MIN(tblCharm.CommunicationMaterialTypeName) AS CommunicationMaterialTypeName,
MIN(tblUp.AttachmentID) AS AttachmentID,
tblOld.SmartFormID, tblOld.isGenerated,
MIN(tblStrange.SupportDocumentTypeID) AS SupportDocumentTypeName
FROM
tblRed
INNER JOIN
tblGreen ON tblRed.StageID = tblGreen.StageID
LEFT OUTER JOIN
tblBlue ON tblRed.RMUserID = tblBlue.UserID
INNER JOIN
tblBrown ON tblRed.EventID = tblBrown.EventID
LEFT OUTER JOIN
tblUp ON tblUp.PhaseID = tblRed.PhaseID
LEFT OUTER JOIN
tblCharm ON tblUp.CommunicationMaterialTypeID = tblCharm.CommunicationMaterialID
AND tblUp.isLatest = 'True'
LEFT OUTER JOIN
tblOld ON tblOld.PhaseID = tblRed.PhaseID
LEFT OUTER JOIN
tblStrange ON tblStrange.PhaseID = tblRed.PhaseID
WHERE
tblRed.Status = 'Active'
AND tblGreen.AuthorQueue = 'History'
AND tblRed.AuthorUserID = #UserID
GROUP BY
tblRed.PhaseID, tblRed.EventID, tblRed.RMUserID, tblRed.BackupRMUserID,
tblRed.AuthorUserID, tblRed.StageID, tblRed.Status,
tblRed.PublicationDateActual, tblGreen.SystemName, tblGreen.StakeholderDisplayName,
tblGreen.StakeholderQueue, tblRed.EventTypeID, tblRed.StageReceivedDate,
tblRed.StageDueDate, tblRed.SubmitDate, tblBlue.Name, tblBlue.Email,
tblBlue.PhoneNumber, tblBrown.EventName, tblOld.SmartFormID, tblOld.isGenerated

Related

Resolve SQL Server consuming long execution

The below query is of a view for which a top 10 * taking 1 minute 58 seconds sometime 2 minutes 30 seconds also, need help to tune the query all the joined tables have indexes already created.
The below query has CTE expressions and multiple joins and case statements. Need help on tuning the below query.
WITH CrmStatus AS
(SELECT DISTINCT
ESTAT,
StatusShortDesc,
sp.ProcessType
FROM refCRMStatus cs WITH (NOLOCK)
INNER JOIN refCRMStatusProfile sp ON sp.Processprofile = cs.ProcessType),
CTEOrgMaan1 AS
(SELECT Sorg.DistributionChannel AS DistributionChannel,
SO.Objectname AS SalesOffCode,
SOr.Objectname AS SalesOrgID,
SGrp.Objectname AS SalesGroup,
dvnb.DivisionName AS Brand,
Sorg.[H_CRMDOrgmanHSK],
Lnkorg.[H_CMRDLinkHSK],
[H_OpportunityHSK]
FROM [dbo].[S_CMRDOrgman] Sorg WITH (NOLOCK)
INNER JOIN [dbo].[L_CMRDLinkOrgman] Lnkorg WITH (NOLOCK) ON Lnkorg.[H_CRMDOrgmanHSK] = Sorg.[H_CRMDOrgmanHSK]
INNER JOIN vw_DivisionorBrand dvnb ON dvnb.DivisionCode = Sorg.DIVISION
INNER JOIN [dbo].[refSalesOfficeCRM] SO ON SO.[SalesOfficeID] = Sorg.SALESOFFICE
INNER JOIN [dbo].[refSalesOrgCRM] SOr ON SOr.[SalesOrgID] = Sorg.SALESORG
INNER JOIN [dbo].[refSalesGroupCRM] SGrp ON SGrp.[SalesGroupID] = Sorg.SalesGroup),
CTEAppoint AS
(SELECT HO.H_OpportunityHSK,
HO.ProcessType AS BusinessTransType,
refPt.ObjectType AS ObjectType,
refPt.processDesc AS ProcessDesc,
LeadGUID AS CRMOrderGUID,
SA.[APPLGUID],
SA.[APPTGUID],
SA.AppntID,
SA.ApptType AS AppointmentType,
SA.ApptText AS TextofAppointment,
SA.[CreatedBy],
SA.[ChangedBy],
SA.Startdate,
SA.FromTime,
SA.[AppntStartTimeZone] AS AppointmentStartTimeZone,
SA.[AppntStartTime] AS AppointmentStartTime,
SA.EndDate,
SA.ToTime,
SA.[AppntEndTimeZone] AS AppointmentEndTimeZone,
SA.[AppntEndTime] AS AppointmentEndTime,
SA.CreationDate,
SA.CreationTime,
SA.TimeStampCreation,
SA.ChangedOn,
SA.LastChangedAt,
SA.[TimeStampChangeTime] AS TimeStampOfChangeTime
FROM [dbo].[H_Opportunity] HO
INNER JOIN [dbo].[L_AppointmentorderADM] LA ON LA.[H_OpportunityHSK] = HO.[H_OpportunityHSK]
INNER JOIN [dbo].s_Appointment SA --with (index ([NonClusteredIndex-20200507-034807]))
ON LA.[L_AppointmentOrderADMHSK] = SA.[L_AppointmentOrderADMHSK]
INNER JOIN [dbo].[refProcessType] refPt ON refPt.[ProcessType] = HO.ProcessType)
SELECT a.*,
CTEOrgMaan.SalesOffCode,
CTEOrgMaan.SalesGroup,
CTEOrgMaan.SalesOrg AS SalesOrgID,
CTEOrgMaan.DistributionChannel,
CTEOrgMaan.Brand
FROM (SELECT DISTINCT
CApp.H_OpportunityHSK,
CApp.BusinessTransType,
CApp.ObjectType,
CApp.ProcessDesc,
CApp.CRMOrderGUID,
CApp.[APPLGUID],
CApp.[APPTGUID],
CApp.AppntID,
CApp.AppointmentType,
CApp.TextofAppointment,
CApp.[CreatedBy],
CApp.[ChangedBy],
CApp.Startdate,
CApp.FromTime,
CApp.AppointmentStartTimeZone,
CApp.AppointmentStartTime,
CApp.EndDate,
CApp.ToTime,
CApp.AppointmentEndTimeZone,
CApp.AppointmentEndTime,
CApp.CreationDate,
CApp.CreationTime,
CApp.TimeStampCreation,
CApp.ChangedOn,
CApp.LastChangedAt,
CApp.TimeStampOfChangeTime,
PARTNERFCT AS PartnerFunction,
rfct.DESCRIPTION AS PartnerDesc,
PartnerNo,
Partnerguid,
MainPartner AS MainPartnerFlag,
St.[Stat] AS Status,
stu.[StatusShortDesc],
CASE WHEN CC.CompanyName IS NOT NULL THEN CC.CompanyName ELSE CI.FullName END AS CustomerName,
CONVERT(varchar(MAX),
CASE
WHEN CC.H_EngageCustomerHSK IS NOT NULL THEN CC.H_EngageCustomerHSK
ELSE CASE
WHEN CI.H_EngageCustomerHSK IS NULL THEN CONVERT(uniqueidentifier, (HASHBYTES('Md5', 'NA')))
ELSE CI.H_EngageCustomerHSK
END
END) AS CustomerHSK,
CASE WHEN CC.CustomerType IS NOT NULL THEN CC.CustomerType ELSE CI.CustomerType END AS CustomerType
FROM [dbo].[H_CMRDPartner] Hp
LEFT JOIN [dbo].[S_CMRPartner] Sp ON Hp.[H_CMRDPartnerHSK] = Sp.[H_CMRDPartnerHSK]
INNER JOIN [dbo].[L_CRMDPartner] LCP ON LCP.[H_CMRDPartnerHSK] = Hp.[H_CMRDPartnerHSK]
LEFT JOIN [dbo].[L_CRMDCustomerPartner] CCP ON CCP.[H_CMRDPartnerHSK] = Hp.[H_CMRDPartnerHSK]
LEFT JOIN S_CustomerCompany CC ON CC.H_EngageCustomerHSK = CCP.[H_EngageCustomerHSK]
LEFT OUTER JOIN S_CustomerIndividual CI ON CI.H_EngageCustomerHSK = CCP.[H_EngageCustomerHSK]
LEFT JOIN CTEAppoint CApp ON CApp.H_OpportunityHSK = LCP.H_OpportunityHSK
INNER JOIN [dbo].[S_CRMOrderADMStatus] St ON St.[H_OpportunityHSK] = CApp.H_OpportunityHSK
INNER JOIN CrmStatus stu ON stu.ESTAT = St.Stat
AND stu.processType = CApp.BusinessTransType
LEFT JOIN refCRMCPartnerFCT rfct ON rfct.[PARTNER_FCT] = Sp.PartnerFCT
WHERE Sp.PartnerFCT = '00000009') a
INNER JOIN vw_getCRMDOrgman_new CTEOrgMaan ON CTEOrgMaan.H_OpportunityHSK = a.H_OpportunityHSK;
GO

DB2 SQL multiple JOIN issue

I have a query with two JOIN and it does not work. I get no errors. It just does not return any records. If I separate my query then it works. What Am I doing wrong here?
When I split up the query I get one record each which is what I should get.
Full query:
SELECT HPOL07.*, #RFC.*, #AAM.*
FROM BPCSPROF.HPOL07
JOIN BPCSPROF.#RFC ON PRFC = #RFC.RFCNUM AND PPRF = #RFC.RFCPRC
AND PGLNO = #RFC.RFCGLN
JOIN BPCSPROF.#AAM ON PPRF = #AAM.AAMPRC AND PGLNO = #AAM.AAMGLN
WHERE PORD = '605400' AND PID <> 'PZ'
Separate queries:
SELECT HPOL07.*, #RFC.*
FROM BPCSPROF.HPOL07
JOIN BPCSPROF.#RFC ON PRFC = #RFC.RFCNUM AND PPRF = #RFC.RFCPRC
AND PGLNO = #RFC.RFCGLN
WHERE PORD = '605400' AND PID <> 'PZ'
SELECT HPOL07.*, #AAM.*
FROM BPCSPROF.HPOL07
JOIN BPCSPROF.#AAM ON PPRF = #AAM.AAMPRC AND PGLNO = #AAM.AAMGLN
WHERE PORD = '605400' AND PID <> 'PZ'
You're doing inner joins, so there must be a record in both #RFC and #AAM for each record in HPOL07...
Is that what you want?
If there's a matching record in #RFC or #AAM, then you'd want to use a LEFT OUTER JOIN
SELECT HPOL07.*, #RFC.*, #AAM.*
FROM BPCSPROF.HPOL07
LEFT OUTER JOIN BPCSPROF.#RFC
ON PRFC = #RFC.RFCNUM AND PPRF = #RFC.RFCPRC
AND PGLNO = #RFC.RFCGLN
LEFT OUTER JOIN BPCSPROF.#AAM
ON PPRF = #AAM.AAMPRC AND PGLNO = #AAM.AAMGLN
WHERE PORD = '605400' AND PID <> 'PZ'
This question could certainly use a table schema but my guess is that PGLNO is a different value between your two joins. If that's the case, the joins aren't going to to work because it is effectively looking for #AAM.AAMGLN = #RFC.RFCGLN in your current query. This is because both joins use the PGLNO value and would need to be the same for both join clauses.
If you want two separate results, #Charles answer should do what you want.
You can also use:
SELECT * FROM A h
LEFT JOIN B pk ON (pk.PKKONZ='010') AND (pk.PKFIRM IN (10, 20 30)) AND h.TPPALN = pk.PKPALN
LEFT JOIN C ar ON (ar.TZKONZ='010') AND (ar.TZFIRM IN (55, 56 ,57)) AND h.TPIDEN = ar.TZIDEN
WHERE ....
ORDER BY ...

Query Performance too Slow

Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.

SQL Server update with joins

I am trying to update a date in a table, based off of a MAX(date) in another table. To get the correct data to link up, I have to do 2 inner joins and 2 left outer joins.
I can select the correct data, it returns a Guid (PersonId) and the Date.
I have to use this information to update my original table. I am having trouble getting this to work, I still getting syntax errors.
update tblqualityassignments as assign
inner join tblrequirementteams as team on assign.guidmemberid = team.guidmemberid
set assign.dtmQAPCLed = dtmTaken
from
(
select reg.guidpersonid, max(certs.dtmTaken) as dtmTaken from tblqualityassignments as assign
inner join tblrequirementteams as team on assign.guidmemberid = team.guidmemberid
inner join tblregisteredusercerts as reg on team.guidpersonid = reg.guidpersonid
left outer join tblcerttaken as certs on certs.guidcertid = reg.guidcertid
left outer join tblCodesCertType as types on types.intcerttypeid = certs.intcerttypeid
where types.intcerttypeid = 1
and assign.guidmemberid = team.guidmemberid
group by reg.guidpersonid as data
)
where data.guidpersonid = team.guidpersonid
Assuming you are using SQL Server for this, then this should work:
UPDATE A
SET A.dtmQAPCLed = dtmTaken
FROM tblqualityassignments AS A
INNER JOIN tblrequirementteams as T
ON A.guidmemberid = T.guidmemberid
INNER JOIN (select reg.guidpersonid, max(certs.dtmTaken) as dtmTaken
from tblqualityassignments as assign
inner join tblrequirementteams as team
on assign.guidmemberid = team.guidmemberid
inner join tblregisteredusercerts as reg
on team.guidpersonid = reg.guidpersonid
left outer join tblcerttaken as certs
on certs.guidcertid = reg.guidcertid
left outer join tblCodesCertType as [types]
on [types].intcerttypeid = certs.intcerttypeid
where [types].intcerttypeid = 1
and assign.guidmemberid = team.guidmemberid
group by reg.guidpersonid) data
ON T.guidpersonid = data.guidpersonid

Making join condition more exclusive causes query to hang

Sorry for the wall of SQL, but I am having some problems with the query below. It seems to never finish executing (it runs for a few minutes, then I kill it). The weird thing is that if I change the join condition for the StudentTestsPre table from TestInstances.fkSchoolYearID = (TestInstancesPre.fkSchoolYearID + 1) to TestInstances.fkSchoolYearID > TestInstancesPre.fkSchoolYearID, then the query returns instantly. How could using a more exclusive join condition cause my query to hang? Seems like that should make the query faster, if anything.
Any ideas?
SELECT *
FROM TestInstances
INNER JOIN StudentTests on StudentTests.fkTestInstanceID = TestInstances.pkTestInstanceID
AND StudentTests.pkStudentTestID IN (SELECT * FROM #tempTests)
INNER JOIN TestInstances TestInstancesPre ON TestInstances.fkSchoolYearID = (TestInstancesPre.fkSchoolYearID + 1)
AND TestInstancesPre.fkTestTypeID = 1 AND TestInstances.fkTestTypeID = 1
INNER JOIN StudentTests StudentTestsPre on StudentTestsPre.fkTestInstanceID = TestInstancesPre.pkTestInstanceID
AND StudentTests.fkStudentID = StudentTestsPre.fkStudentID
INNER JOIN StudentScores_Subject s ON s.fkStudentTestID = StudentTests.pkStudentTestID
AND s.fkTest_SubjectID IN (SELECT pkTestSubjectID FROM MM_Test_Subjects WHERE fkCSTStrandID IN (SELECT number FROM itot(#strAcceptableStrands, N',')) AND fkTestTypeID = 1)
AND s.fkScoreTypeID = 3
INNER JOIN StudentScores_Subject sPre ON sPre.fkStudentTestID = StudentTestsPre.pkStudentTestID
AND sPre.fkTest_SubjectID IN (SELECT pkTestSubjectID FROM MM_Test_Subjects WHERE fkCSTStrandID IN (SELECT number FROM itot(#strAcceptableStrands, N',')) AND fkTestTypeID = 1)
AND sPre.fkScoreTypeID = 3
INNER JOIN MM_Test_PL_SS_Ranges r ON r.fkTest_SubjectID = s.fkTest_SubjectID
AND r.fkSchoolYearID = TestInstances.fkSchoolYearID
AND r.fkTestTypeID = TestInstances.fkTestTypeID
AND (r.fkGradeID = StudentTests.fkGradeID OR r.fkGradeID = 99)
INNER JOIN MM_Test_PL_SS_Ranges rPre ON rPre.fkTest_SubjectID = sPre.fkTest_SubjectID
AND rPre.fkSchoolYearID = TestInstancesPre.fkSchoolYearID
AND rPre.fkTestTypeID = TestInstancesPre.fkTestTypeID
AND (rPre.fkGradeID = StudentTestsPre.fkGradeID OR rPre.fkGradeID = 99)
INNER JOIN StudentScores_Subject s2 ON s2.fkStudentTestID = StudentTests.pkStudentTestID
AND s2.fkTest_SubjectID = s.fkTest_SubjectID
AND s2.fkScoreTypeID = 2
INNER JOIN StudentScores_Subject sPre2 ON sPre2.fkStudentTestID = StudentTestsPre.pkStudentTestID
AND sPre2.fkTest_SubjectID = sPre.fkTest_SubjectID
AND sPre2.fkScoreTypeID = 2
INNER JOIN Students on Students.pkStudentID = StudentTests.fkStudentID
thanks for the help!
For SO, here's the above script with alternative formatting & short aliases:
SELECT *
FROM TestInstances
INNER JOIN StudentTests st
ON st.fkTestInstanceID = ti.pkTestInstanceID
AND st.pkStudentTestID IN (SELECT * FROM #tempTests)
INNER JOIN TestInstances tiPre
ON ti.fkSchoolYearID = (tiPre.fkSchoolYearID + 1)
AND tiPre.fkTestTypeID = 1 AND ti.fkTestTypeID = 1
INNER JOIN StudentTests stPre
ON stPre.fkTestInstanceID = tiPre.pkTestInstanceID
AND st.fkStudentID = stPre.fkStudentID
INNER JOIN StudentScores_Subject s
ON s.fkStudentTestID = st.pkStudentTestID
AND s.fkTest_SubjectID IN (
SELECT pkTestSubjectID
FROM MM_Test_Subjects
WHERE fkCSTStrandID IN (
SELECT number FROM itot(#strAcceptableStrands, N','))
AND fkTestTypeID = 1)
AND s.fkScoreTypeID = 3
INNER JOIN StudentScores_Subject sPre
ON sPre.fkStudentTestID = stPre.pkStudentTestID
AND sPre.fkTest_SubjectID IN (
SELECT pkTestSubjectID
FROM MM_Test_Subjects
WHERE fkCSTStrandID IN (
SELECT number FROM itot(#strAcceptableStrands, N','))
AND fkTestTypeID = 1)
AND sPre.fkScoreTypeID = 3
INNER JOIN MM_Test_PL_SS_Ranges r
ON r.fkTest_SubjectID = s.fkTest_SubjectID
AND r.fkSchoolYearID = ti.fkSchoolYearID
AND r.fkTestTypeID = ti.fkTestTypeID
AND (r.fkGradeID = st.fkGradeID OR r.fkGradeID = 99)
INNER JOIN MM_Test_PL_SS_Ranges rPre
ON rPre.fkTest_SubjectID = sPre.fkTest_SubjectID
AND rPre.fkSchoolYearID = tiPre.fkSchoolYearID
AND rPre.fkTestTypeID = tiPre.fkTestTypeID
AND (rPre.fkGradeID = stPre.fkGradeID OR rPre.fkGradeID = 99)
INNER JOIN StudentScores_Subject s2
ON s2.fkStudentTestID = st.pkStudentTestID
AND s2.fkTest_SubjectID = s.fkTest_SubjectID
AND s2.fkScoreTypeID = 2
INNER JOIN StudentScores_Subject sPre2
ON sPre2.fkStudentTestID = stPre.pkStudentTestID
AND sPre2.fkTest_SubjectID = sPre.fkTest_SubjectID
AND sPre2.fkScoreTypeID = 2
INNER JOIN Students
ON Students.pkStudentID = st.fkStudentID
Take a look at your execution plan. My guess is that doing the calculation in the join aka (TestInstancesPre.fkSchoolYearID + 1) is causing indexes not be used correctly. An easy way to test this would be to change your join to:
TestInstances.fkSchoolYearID = TestInstancesPre.fkSchoolYearID
I have seen performance go way down when doing funky stuff in a join. Things like:
ON t1.column1 = ISNULL(t2.myColumn, 1)
I believe this is because the query becomes non-sargable. Take a look at this SO post for more details on that.
By having a calculation in your comparison, it can invalidate the use of an index. This usually happens when the datatype of the calculation result is different from the datatype of the column being indexed. Sometimes the cost of calculation is large if it has to be repeated enough times (eg from lots of joins). One solution is to store the calculated value in a special column, eg:
CREATE TABLE TestInstances (
...
nextSchoolYearID int);
And use a trigger or logic to maintain nextSchoolYearID = fkSchoolYearID + 1, then use
ON TestInstances.fkSchoolYearID = TestInstancesPre.nextSchoolYearID)
Also, you have AND StudentTests.pkStudentTestID IN (SELECT * FROM #tempTests) in the first join's on clause, but the values in #tempTests are not related to either table.
Try moving that predicate to a where clause at the end, ie:
SELECT
...
WHERE StudentTests.pkStudentTestID IN (SELECT * FROM #tempTests)
Doing this means SELECT * FROM #tempTests will only get executed once, instead of being executed for every row combination of TestInstances and StudentTests.