I'm a part-time accidental DBA and I've run into problem. Unfortunately, do to some restrictions on how the software is running, I can't do the obvious and turn the sub-query into a join. Is there a way to index this thing to have it perform better?
I have select statement that on its own, takes about 2 seconds to return 28000 records. When I add a subquery to the SELECT, it explodes into over a minute and change.
The subquery, separately, also takes about 2 seconds to return data.
ADDENDUM: The XML for the execution plan.
The OpenIssuesTBL.AssignedBy and OpenIssuesTBL.Resp columns are not stored as wild cards. We pass variables in to them in code, the wildcards are just so I can grab all the records in a similar way as the 'show all records' button we have.
To explain the design a little bit, our code can add additional columns on the fly by using these sub-queries in the select statement. We pull them from another table and just insert them into the query we use to populate a search screen. Most of the time, this works without a problem. For some reason, this query is just dog slow.
SELECT OpenIssuesTBL.IssueID
, OpenIssuesTBL.Category
, qryCOCompanyDBQualUnion.CompanyName
, CASE
WHEN bitConfidential = 0
THEN OpenIssuesTBL.Issue
ELSE 'Confidential'
END AS Issue
, OpenIssuesTBL.OpenDate
, OpenIssuesTBL.Priority
, OpenIssuesTBL.Duration
, OpenIssuesTBL.DueDate
, OpenIssuesTBL.Resp
, CASE
WHEN bitConfidential = 0
THEN OpenIssuesTBL.Progress
ELSE 'Confidential'
END AS Progress
, OpenIssuesTBL.ClosedDate AS StatusDate
, OpenIssuesTBL.AssignedBy
, DBQualityUtilityTBL.CompanyName AS Site
, tblIssueTypeList.strIssueType
, OpenIssuesTBL.strIssueStatus
, OpenIssuesTBL.strProductNum
, OpenIssuesTBL.ynSystemGenerated
, OpenIssuesTBL.strSuggestion
, OpenIssuesTBL.strSource
, OpenIssuesTBL.memIssueDialog
, tblIssueTimeLookup.strTimeDesc
, OpenIssuesTBL.strComponent
, OpenIssuesTBL.intPercentComplete
, tblUDFIssues.strUDF1
, tblUDFIssues.strUDF2
, tblUDFIssues.strUDF3
, tblUDFIssues.strUDF4
, tblUDFIssues.strUDF5
, tblUDFIssues.strUDF6
, tblUDFIssues.strUDF7
, tblUDFIssues.strUDF8
, tblUDFIssues.strUDF9
, tblUDFIssues.strUDF10
, tblUDFIssues.strUDF11
, tblUDFIssues.strUDF12
, CASE ISNULL(qryIssuesRYG.RYGColor, 32768)
WHEN 255
THEN 'Red'
WHEN 32768
THEN 'Green'
WHEN 65535
THEN 'Yellow'
END AS RYG
, qryWMIssueDurationHrs.DurationHours
, CASE
WHEN OpenIssuesTBL.bitConfidential = 0
THEN ''
ELSE 'X'
END AS Confidential
, CASE
WHEN OpenIssuesTBL.bitRequiresVerify = 0
THEN ''
ELSE 'X'
END AS ReqsVer
, OpenIssuesTBL.strVerifiedBy
, OpenIssuesTBL.dteVerified
, CASE
WHEN OpenIssuesTBL.bitRequiresVerify <> 0
THEN 'Verified BY'
ELSE ''
END AS lblVerifiedBy
, CASE
WHEN OpenIssuesTBL.bitRequiresVerify <> 0
THEN [strVerifiedBy]
ELSE ''
END AS VerifiedBy
, CASE
WHEN OpenIssuesTBL.bitRequiresVerify <> 0
THEN 'Verified Date'
ELSE ''
END AS lblVerifiedDate
, CASE
WHEN OpenIssuesTBL.bitRequiresVerify <> 0
THEN [dteVerified]
ELSE NULL
END AS VerifiedDate
, qryWMWorkflowIssueNextStep.strStep
, qryWMWorkflowIssueNextStep.strResp
, qryWMWorkflowIssueNextStep.dteDue
, tblWorkflowSetup.strWorkflowName + ' (Rev. ' + tblWorkflowSetupRevisions.strRevisionNo + ')' AS WorkflowName
, OpenIssuesTBL.memWorkflowNotes
, (
SELECT TOP 1
qryIssueRespSupervisor._Supvr
FROM qryIssueRespSupervisor
WHERE qryIssueRespSupervisor.lngFKIssueID = OpenIssuesTBL.IssueID
)
FROM qryWMIssueDurationHrs
RIGHT OUTER JOIN qryWMWorkflowIssueNextStep
RIGHT OUTER JOIN OpenIssuesTBL ON qryWMWorkflowIssueNextStep.IssueID = OpenIssuesTBL.IssueID
LEFT OUTER JOIN tblWorkflowSetupRevisions ON OpenIssuesTBL.lngfkWorkflowRevisionID = tblWorkflowSetupRevisions.lngWorkflowSetupRevisionID
LEFT OUTER JOIN tblWorkflowSetup ON OpenIssuesTBL.lngfkWorkflowSetupID = tblWorkflowSetup.lngWorkflowSetupID ON qryWMIssueDurationHrs.IssueID = OpenIssuesTBL.IssueID
LEFT OUTER JOIN qryIssuesRYG ON OpenIssuesTBL.IssueID = qryIssuesRYG.IssueID
LEFT OUTER JOIN tblUDFIssues ON OpenIssuesTBL.IssueID = tblUDFIssues.lngIssueID
LEFT OUTER JOIN qryCOCompanyDBQualUnion ON OpenIssuesTBL.CompanyID = qryCOCompanyDBQualUnion.CompanyID
LEFT OUTER JOIN tblIssueTypeList ON OpenIssuesTBL.IssueTypeID = tblIssueTypeList.lngIssueTypeID
LEFT OUTER JOIN DBQualityUtilityTBL ON OpenIssuesTBL.LocationID = DBQualityUtilityTBL.CompanyID
LEFT OUTER JOIN tblIssueTimeLookup ON OpenIssuesTBL.bteDurUnits = tblIssueTimeLookup.lngTimeID
WHERE (
bitConfidential = 0
OR OpenIssuesTBL.AssignedBy = '%'
OR OpenIssuesTBL.Resp = '%'
)
The subquery is a view–it looks like this.
CREATE VIEW qryIssueRespSupervisor AS
(
SELECT EmployeeTBL_1.FirstName + ' ' + EmployeeTBL_1.LastName AS _Supvr
, i1.IssueID AS lngFKIssueID
FROM dbo.EmployeeTBL
INNER JOIN dbo.PosDescriptTBL ON dbo.EmployeeTBL.PositionNo = dbo.PosDescriptTBL.PositionNo
INNER JOIN dbo.PosDescriptTBL AS PosDescriptTBL_1 ON dbo.PosDescriptTBL.lngfkReportsToID = PosDescriptTBL_1.PositionNo
INNER JOIN dbo.EmployeeTBL AS EmployeeTBL_1 ON PosDescriptTBL_1.PositionNo = EmployeeTBL_1.PositionNo
INNER JOIN dbo.StatusLookupTBL ON EmployeeTBL_1.Active = dbo.StatusLookupTBL.StatusType
INNER JOIN dbo.qryTREmployeeFullName ON dbo.EmployeeTBL.EmployeeID = dbo.qryTREmployeeFullName.EmployeeID
INNER JOIN dbo.OpenIssuesTBL AS i1 ON dbo.qryTREmployeeFullName.EName = i1.Resp
WHERE (
dbo.StatusLookupTBL.intHide = 0
)
)
Best Answer
Your
Select
statement withTOP 1
in a sub query is a killer. When you are running your query, this statement will run for each row. depending on number of rows your main statement is returning, you can imagine the time it is going to take. In my opinion, what you can try is using yourview
'sSelect
statement withGROUP BY
as common table expression (or change theview
to use group by, if possible) so it always returns a top record a particular Id. (I can not see your table design so I am not sure which aggregate you can use toGROUP BY
your statement but May be group it withMAX(IssueId)
) once you have that, all you need is simpleINNER JOIN
orLEFT OUTER JOIN
in your main query.Hope this is making sense.