Query I need to be sped up - sql

I have this query in SQL Server 2005:
SELECT J.JobID,
dbo.tblCustomers.Name AS CustomerName,
J.CustomerJobNumber,
J.JobName,
(CASE WHEN [tblCustomers].[CoreCust] = 0 THEN 'AUXILIARY' ELSE 'CORE' END) AS Department,
J.JobStatusID,
dbo.tblJobTypes.JobType
FROM dbo.tblJobs (NOLOCK) AS J
INNER JOIN dbo.tblCustomers (NOLOCK) ON J.CustomerID = dbo.tblCustomers.CustomerID
INNER JOIN dbo.tblJobTypes (NOLOCK) ON J.JobTypeID = dbo.tblJobTypes.JobTypeID
INNER JOIN dbo.tblDepartments (NOLOCK) ON J.DepartmentId = dbo.tblDepartments.DepartmentID
WHERE (J.Closed = 0)
AND (J.Invoiced = 0)
AND (J.Active = 1)
AND (dbo.fncIsAllPointsDelivered(J.JobID) = 1)
AND (J.DepartmentId <> 2)
This query is taking too long to run, and I know the problem is the UDF - (dbo.fncIsAllPointsDelivered(J.JobID) = 1) -.
The SQL for the UDF is here:
DECLARE #DetailCount int
DECLARE #TrackingCount int
SELECT #DetailCount = COUNT(*)
FROM [dbo].[tblLoadDetails] (NOLOCK)
WHERE JobId = #JobId
SELECT #TrackingCount = COUNT(*)
FROM [dbo].[tblLoadDetails] (NOLOCK)
WHERE JobId = #JobId AND Delivered = 1
IF(#DetailCount = #TrackingCount AND #DetailCount > 0)
RETURN 1
RETURN 0
All of this runs blazingly fast unless the job has a large number of load details in it. I am trying to think of a way to either make the UDF faster or get rid of the need for the UDF, but I am at a loss. I am hoping some of you SQL gurus will be able to help me.

SELECT *
FROM tblJobs j
INNER JOIN
tblCustomers c
ON c.CustomerID = J.CustomerID
INNER JOIN
tblJobTypes jt
ON jt.JobTypeID = J.JobTypeID
INNER JOIN
tblDepartments d
ON d.DepartmentID = J.DepartmentId
WHERE J.Closed = 0
AND J.Invoiced = 0
AND J.Active = 1
AND J.DepartmentId <> 2
AND J.JobID IN
(
SELECT JobID
FROM tblLoadDetails
)
AND J.JobID NOT IN
(
SELECT JobID
FROM tblLoadDetails
WHERE Delivered <> 1
)
Create a composite index on these fields:
tblJobs (Closed, Invoiced, Active) INCLUDE (DepartmentID)
If your tblLoadDetails.Delivered is a bit field, then create the following index:
tblLoadDetail (JobID, Delivered)
and rewrite the last condition as this:
SELECT *
FROM tblJobs j
INNER JOIN
tblCustomers c
ON c.CustomerID = J.CustomerID
INNER JOIN
tblJobTypes jt
ON jt.JobTypeID = J.JobTypeID
INNER JOIN
tblDepartments d
ON d.DepartmentID = J.DepartmentId
WHERE J.Closed = 0
AND J.Invoiced = 0
AND J.Active = 1
AND J.DepartmentId <> 2
AND
(
SELECT TOP 1 Delivered
FROM tblLoadDetails ld
WHERE ld.JobID = j.JobID
ORDER BY
Delivered
) = 1

I'm working this from the top of my head, so I haven't tried this out. But I think you could do this to remove the function. Replace the call to the function with these two clauses. This is assuming that 'Delivered' is a BIT field:
AND EXISTS (SELECT 1 FROM tblLoadDetails WHERE JobID = J.JobID)
AND NOT EXISTS (SELECT 1 FROM tblLoadDetails WHERE JobID = J.JobID AND Delivered = 0)
The AND EXISTS covers the UDF's #DetailCount > 0 check; the AND NOT EXISTS then covers the #DetailCount = #TrackingCount, the assumption I'm making is that you're looking to see if the job exists and everying to do with that job has been delivered. so if there's even one thing that hasn't been delivered, it needs to be excluded.
As mentioned: from top of head, and thus not tested or not profiled. I think I've got the logic right. If not, it should be a simple variation thereof.

Related

The SQL Server query is taking too long to load the data

The below query is actually a view which is being used to display the cash payment report. But it is taking too much of time to load the data
SELECT
Billing_AccountPaymentDate.DueDate,
SUM(Billing_AccountCharge.NetAmount) AS NetCharges,
ISNULL(SUM(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances + AccountChargePayment.SchoolRemittancesPending), 0) / SUM(Billing_AccountCharge.NetAmount) AS PercentCollected,
SUM(Billing_AccountCharge.NetAmount - ISNULL(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances + AccountChargePayment.SchoolRemittancesPending, 0)) AS RemainingBalance,
Billing_AccountPaymentDate.RemittanceEffectiveDate,
Billing_Account.SchoolId,
ISNULL(SUM(AccountChargePayment.SchoolPayments), 0) AS SchoolPayments,
ISNULL(SUM(AccountChargePayment.SchoolRemittances), 0) AS SchoolRemittances,
ISNULL(SUM(AccountChargePayment.SchoolRemittancesPending), 0) AS SchoolRemittancesPending,
Billing_Account.SchoolYearId,
ISNULL(SUM(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances), 0) AS TotalReceipts
FROM
Billing_AccountCharge
INNER JOIN
Billing_AccountInvoice ON
Billing_AccountInvoice.AccountInvoiceId = Billing_AccountCharge.AccountInvoiceId
INNER JOIN
Billing_Account ON
Billing_Account.AccountId = Billing_AccountInvoice.AccountId
INNER JOIN
Billing_PaymentMethod ON
Billing_PaymentMethod.PaymentMethodId = CASE WHEN Billing_AccountInvoice.AutomaticPaymentEligible = 1 THEN Billing_Account.PaymentMethodId ELSE 3 END -- Send Statements
INNER JOIN
Billing_AccountPaymentDate ON
Billing_AccountPaymentDate.AccountPaymentMethodId = Billing_PaymentMethod.AnticipatedAccountPaymentMethodId AND
Billing_AccountPaymentDate.DueDate = Billing_AccountInvoice.DueDate AND
Billing_AccountPaymentDate.HoldForFee = Billing_Account.HoldPaymentForFee
INNER JOIN
Billing_ChargeItem ON
Billing_ChargeItem.ChargeItemId = Billing_AccountCharge.ChargeItemId
LEFT OUTER JOIN
(
SELECT
Billing_AccountChargePayment.AccountChargeId,
SUM(CASE WHEN Billing_AccountPayment.AccountPaymentTypeId = 9 THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolPayments,
SUM(CASE WHEN Billing_AccountChargePayment.SchoolRemittanceId IS NOT NULL THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolRemittances,
SUM(CASE WHEN Billing_AccountChargePayment.SchoolRemittanceId IS NULL AND Billing_AccountPayment.AccountPaymentTypeId <> 9 THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolRemittancesPending
FROM
Billing_AccountChargePayment
INNER JOIN
Billing_AccountPayment ON
Billing_AccountPayment.AccountPaymentId = Billing_AccountChargePayment.AccountPaymentId
GROUP BY
Billing_AccountChargePayment.AccountChargeId
) AccountChargePayment ON
AccountChargePayment.AccountChargeId = Billing_AccountCharge.AccountChargeId
WHERE
Billing_AccountInvoice.AccountInvoiceStatusId <> 4 AND -- Voided
Billing_ChargeItem.RemitToSchool = 1
AND Billing_Account.[SchoolId] = 6 --hard code in a school with data
AND Billing_Account.[SchoolYearId] = 12 --hard code in a school year with data
GROUP BY
Billing_AccountPaymentDate.DueDate,
Billing_AccountPaymentDate.RemittanceEffectiveDate,
Billing_Account.SchoolId,
Billing_Account.SchoolYearId
HAVING
SUM(Billing_AccountCharge.NetAmount) <> 0
order by Billing_AccountPaymentDate.DueDate ASC
It looks like the inner query in the left join is taking too much of time, both the tables already have non clustered index, I tried taking those tables outside but the data is not accurate
Use CTE instead of subquery and do all calculation there instead of in Left outer join. Moreover, use with(nolock) whenever you fetch data. Still your query is taking much more time then You should implement proper indexing.
WITH PaymentData AS (
SELECT
acp.AccountChargeId,
SUM(
CASE
WHEN ap.AccountPaymentTypeId = 9 THEN acp.Amount
ELSE 0
END
) AS SchoolPayments,
SUM(
CASE
WHEN acp.SchoolRemittanceId IS NOT NULL THEN acp.Amount
ELSE 0
END
) AS SchoolRemittances,
SUM(
CASE
WHEN acp.SchoolRemittanceId IS NULL AND ap.AccountPaymentTypeId <> 9 THEN acp.Amount
ELSE 0
END
) AS SchoolRemittancesPending
FROM
Billing_AccountChargePayment acp WITH(NOLOCK)
INNER JOIN Billing_AccountPayment ap WITH(NOLOCK) ON acp.AccountPaymentId = ap.AccountPaymentId
GROUP BY
acp.AccountChargeId
)
SELECT
apd.DueDate,
SUM(ac.NetAmount) AS NetCharges,
COALESCE(
SUM(pd.SchoolPayments + pd.SchoolRemittances + pd.SchoolRemittancesPending),
0
) / SUM(ac.NetAmount) AS PercentCollected,
SUM(ac.NetAmount - COALESCE(pd.SchoolPayments, 0) - COALESCE(pd.SchoolRemittances, 0) - COALESCE(pd.SchoolRemittancesPending, 0)) AS RemainingBalance,
apd.RemittanceEffectiveDate,
a.SchoolId,
COALESCE(SUM(pd.SchoolPayments), 0) AS SchoolPayments,
COALESCE(SUM(pd.SchoolRemittances), 0) AS SchoolRemittances,
COALESCE(SUM(pd.SchoolRemittancesPending), 0) AS SchoolRemittancesPending,
a.SchoolYearId,
COALESCE(SUM(pd.SchoolPayments + pd.SchoolRemittances), 0) AS TotalReceipts
FROM
Billing_AccountCharge ac WITH(NOLOCK)
INNER JOIN Billing_AccountInvoice ai WITH(NOLOCK) ON ac.AccountInvoiceId = ai.AccountInvoiceId
INNER JOIN Billing_Account a WITH(NOLOCK) ON ai.AccountId = a.AccountId
INNER JOIN Billing_PaymentMethod pm WITH(NOLOCK) ON pm.PaymentMethodId = CASE
WHEN ai.AutomaticPaymentEligible = 1 THEN a.PaymentMethodId
ELSE 3
END
INNER JOIN Billing_AccountPaymentDate apd WITH(NOLOCK) ON
apd.AccountPaymentMethodId = pm.AnticipatedAccountPaymentMethodId AND
apd.DueDate = ai.DueDate AND
apd.HoldForFee = a.HoldPaymentForFee
INNER JOIN Billing_ChargeItem ci WITH(NOLOCK) ON ac.ChargeItemId = ci.ChargeItemId
LEFT OUTER JOIN PaymentData pd WITH(NOLOCK) ON ac.AccountChargeId = pd.AccountChargeId
WHERE
ai.AccountInvoiceStatusId <> 4 AND
ci.RemitToSchool = 1 AND
a.SchoolId = 6 AND
a.SchoolYearId = 12
GROUP BY
apd.DueDate,
apd.RemittanceEffectiveDate,
a.SchoolId,
a.SchoolYearId
HAVING
SUM(ac.NetAmount) <> 0
ORDER BY
apd.DueDate ASC;

Where Clause Using Conditional Statement

i have query below
SELECT #RoleUser = MR.Code FROM MasterRole MR INNER JOIN MasterUsersRole MUR ON MR.Id = MUR.RoleId
INNER JOIN MasterUsers MU ON Mu.UserCode = MUR.UserCode
WHERE MU.UserCode = #UserLoginID
select 1 Num
, MyHistory.ID
, MyHistory.RequestNumber
, MyHistory.FlowID
, MyHistory.FlowProcessStatusID
from
(
select *
from Requests R
inner join
(
--DECLARE #UserLoginID nvarchar(200) = 'dum.testing.3'
select distinct
RequestID
from dbo.RequestTrackingHistory RTH
where IIF(#UserLoginID = 'admin', #UserLoginID, RTH.CreatedBy) = #UserLoginID
OR ( CreatedBy IN
SELECT Mu.UserCode from MasterUsers MU
INNER JOIN MasterUsersRole MUR ON MU.UserCode = MUR.UserCode
INNER JOIN MasterRole MR ON MUR.RoleId = MR.Id
WHERE MR.Code = #RoleUser
)
)
) RT on R.ID = RT.RequestID
) as MyHistory
inner join MasterFlow F on MyHistory.FlowID = F.ID
inner join
(
select FP.ID
, FP.Name
, FP.AssignType
, FP.AssignTo
, FP.IsStart
, case FP.AssignType
when 'GROUP' then
G.Name
end as 'AssignToName'
from MasterFlowProcess FP
left join dbo.MasterRole G on FP.AssignTo = G.ID and FP.AssignType = 'GROUP'
) FP on MyHistory.FlowProcessID = FP.ID
inner join MasterFlowProcessStatus FPS on MyHistory.FlowProcessStatusID = FPS.ID
left join MasterFlowProcessStatusNext FPSN on FPS.ID = FPSN.ProcessStatusFlowID
left join MasterFlowProcess FPN on FPSN.NextProcessFlowID = FPN.ID
left JOIN MasterRole MR ON MR.Id = FPN.AssignTo
left join MasterUsersRole MUR on MR.Id = MUR.RoleId
left join MasterUsers MURO on MUR.UserCode = MURO.UserCode
inner join MasterUsers UC on MyHistory.CreatedBy = UC.UserCode
left join MasterUsers UU on MyHistory.UpdatedBy = UU.UserCode
LEFT JOIN RequestMT RMT ON MyHistory.ID = RMT.RequestID
LEFT JOIN RequestGT RGT ON MyHistory.ID = RGT.RequestID
left join (SELECT sum(QtyCU) countQty , RequestId from dbo.RequestGTDetail where IsActive = 1 group by RequestId) RGTD on RGTD.RequestId = RGT.RequestId
left join (SELECT sum(QtyPCS) countQty , RequestId from dbo.RequestMTDetail where IsActive = 1 group by RequestId) RMTD on RMTD.RequestId = RMT.RequestId
left join (SELECT COUNT(IIF(returnable = 0, returnable, null)) countReturnable , RequestId from dbo.RequestMTDetail group by RequestId) RMTR on RMTR.RequestId = RMT.RequestId
left JOIN dbo.MasterDistributor md ON md.Code = RGT.CustId or md.Code = RMT.CustId
left JOIN dbo.MasterUsersDistributor MUD ON MUD.UserCode = MURO.UserCode AND md.Code = MUD.DistributorCode
LEFT JOIN dbo.MasterReason MRMT ON RMT.ReasonId = MRMT.Id
LEFT JOIN dbo.MasterReason MRGT ON RGT.ReasonId = MRGT.Id
LEFT JOIN dbo.MasterDistributorGroup MDG ON MDG.Id = MD.GroupId
OUTER APPLY dbo.FnGetHistoryApproveDate(MyHistory.Id) AS x
where REPLACE(FPS.Name, '#Requestor', uc.Name) <> 'DRAFT'
AND MUD.DistributorCode IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = #UserLoginID)
i want to add some logic in where clause
this line
==> AND MUD.DistributorCode IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = #UserLoginID)
it depend on the #RoleUser variable, if #RoleUser IN ('A','B') then where clause above is executed, but if #RoleUser Not IN ('A','B') where clause not executed
i,m trying this where clause
AND IIF(#RoleUser IN ('A','B'), MUD.DistributorCode, #RoleUser) IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = IIF(#RoleUser IN ('A','B'), #UserLoginID, NULL))
it didn't work, only executed if #RoleUser IS ('A','B') other than that it return 0 record
any help or advice is really appreciated
thank you
The cleanest way I'm implemented these kind of crazy rules is a
holderTable
and a countVariable against the holder table.
I'll give a generic examples.
This is a "approach" and "philosophy", not a specific answer....with complex WHERE clauses.
DECLARE #customerCountryCount int
DECLARE #customerCountry TABLE ( CountryName varchar(15) )
if ( "the moon is blue on tuesday" ) /* << whatever rules you have */
BEGIN
INSERT INTO #customerCountry SELECT "Honduras" UNION ALL SELECT "Malaysia"
END
if ( "favorite color = green" ) /* << whatever rules you have */
BEGIN
INSERT INTO #customerCountry SELECT "Greenland" UNION ALL SELECT "Peru"
END
SELECT #customerCountryCount = COUNT(*) FROM #customerCountry
Select * from dbo.Customers c
WHERE
(#customerCountryCount = 0)
OR
( exists (select null from #customerCountry innerVariableTable where UPPER(innerVariableTable.CountryName) = UPPER(c.Country) ))
)
This way, instead of putting all the "twisted logic" in an overly complex WHERE statement..... you have "separation of concerns"...
Your inserts into #customerCountry are separated from your use of #customerCountry.
And you have the #customerCountryCount "trick" to distinguish when nothing was used.
You can add a #customerCountryNotExists table as well, and code it to where not exists.
As a side note, you may want to try using a #temp table (instead of a #variabletable (#customerCountry above)... and performance test these 2 options.
There is no "single answer". You have to "try it out".
And many many variables go into #temp table performance (from a sql-server SETUP, not "how you code a stored procedure". That is way outside the scope of this question.
Here is a SOF link to "safe" #temp table usage.
Temporary table in SQL server causing ' There is already an object named' error

Else if in my select statement

I want to have an else if in my select statement i have already tried using case when but the results are not so accurate
heres a snippet of my scripts
select distinct t.MovementDate, t.ContractMovementID, t.GID,t.ReferenceGID,
p.refno, t.amount,convert(date,t.CreatedDate) as createdDat
from
LIF_MGM_T_Contract p
inner join LIF_MMS_T_PolicySuspense s with (nolock)
on s.ContractGID = p.GID
inner join LIF_TMS_T_FinancialTransaction t with (nolock)
on t.ContractGID = p.GID
where
p.refno = '1030642 - 1 - Mohahlaula'
and t.ReversedIndicator = 1
and t.counter = (select min(counter)
from LIF_TMS_T_FinancialTransaction t2 with (nolock)
where t2.ContractGID = p.GID
and t2.ReversedIndicator = 1
and t2.MovementDate = t.MovementDate )
So i want a else if t2.reversedindicator = 0 and date = getdate() return results.. Hope this makes sense

SQl Error : Each GROUP BY expression must contain at least one column that is not an outer reference [duplicate]

This question already has answers here:
Each GROUP BY expression must contain at least one column that is not an outer reference
(8 answers)
Closed 6 years ago.
I get this error
Each GROUP BY expression must contain at least one column that is not an outer reference
while running this query:
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN
#tmpInstallParts_Temp installpartdetails ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END
) = 1
INNER JOIN
partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN
partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN
partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y' AND
ima.ipp_ID IN (SELECT ipp.ipp_id
FROM partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp ON (ipp.ipp_id = tmp.InstallingPartIPPId OR
(CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1
)
GROUP BY
ima.ipp_id
Can someone help me?
This is the text of the query from the first revision of the question.
In later revisions you removed the last closing bracket ) and the query became syntactically incorrect. You'd better check and fix the text of the question and format the text of the query, so it is readable.
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1)
GROUP BY
ima.ipp_id
)
With this formatting it is clear now that there is a subquery with GROUP BY.
Most likely it is just a typo: you meant to write GROUP BY ipp.ipp_id instead of GROUP BY ima.ipp_id.
If you really wanted to have the GROUP BY not in a subquery, but in the main SELECT, then you misplaced the closing bracket ) and the query should look like this:
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1)
)
GROUP BY
ima.ipp_id
In any case, proper formatting of the source code can really help.
Group By ima.ipp_id
should be applicable to outer query. Because of incorrect placement of '(' it was applying to inner query.
Now after correcting the query,it's working fine without any issues.
Final Query is :
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END ) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END ) =1)
)
GROUP BY ima.ipp_id
Thank you all.

How can I optimize the SQL query?

I have a query an SQL query as follows, can anybody suggest any optimization for this; I think most of the effort is being done for the Union operation - is there anything else can be done to get the same result ?
Basically I wanna query first portion of the UNION and if for each record there is no result then the second portion need to be run. Please help.
:
SET dateformat dmy;
WITH incidentcategory
AS (
SELECT 1 ord, i.IncidentId, rl.Description Category FROM incident i
JOIN IncidentLikelihood l ON i.IncidentId = l.IncidentId
JOIN IncidentSeverity s ON i.IncidentId = s.IncidentId
JOIN LikelihoodSeverity ls ON l.LikelihoodId = ls.LikelihoodId AND s.SeverityId = ls.SeverityId
JOIN RiskLevel rl ON ls.RiskLevelId = rl.riskLevelId
UNION
SELECT 2 ord, i.incidentid,
rl.description Category
FROM incident i
JOIN incidentreportlikelihood l
ON i.incidentid = l.incidentid
JOIN incidentreportseverity s
ON i.incidentid = s.incidentid
JOIN likelihoodseverity ls
ON l.likelihoodid = ls.likelihoodid
AND s.severityid = ls.severityid
JOIN risklevel rl
ON ls.risklevelid = rl.risklevelid
) ,
ic AS (
SELECT ROW_NUMBER() OVER (PARTITION BY i.IncidentId ORDER BY (CASE WHEN incidentTime IS NULL THEN GETDATE() ELSE incidentTime END) DESC,ord ASC) rn,
i.incidentid,
dbo.Incidentdescription(i.incidentid, '',
'',
'', '')
IncidentDescription,
dbo.Dateconverttimezonecompanyid(closedtime,
i.companyid)
ClosedTime,
incidenttime,
incidentno,
Isnull(c.category, '')
Category,
opencorrectiveactions,
reportcompleted,
Isnull(classificationcompleted, 0)
ClassificationCompleted,
Cast (( CASE
WHEN closedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
IncidentClosed,
Cast (( CASE
WHEN investigatorfinishedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationFinished,
Cast (( CASE
WHEN investigationcompletetime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationComplete,
Cast (( CASE
WHEN investigatorassignedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigatorAssigned,
Cast (( CASE
WHEN (SELECT Count(*)
FROM incidentinvestigator
WHERE incidentid = i.incidentid
AND personid = 1588
AND tablename = 'AdminLevels') = 0
THEN 0
ELSE 1
END ) AS BIT)
IncidentInvestigator,
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader,
incidentstatus,
incidentstatussearch
FROM incident i
LEFT OUTER JOIN incidentcategory c
ON i.incidentid = c.incidentid
WHERE i.isdeleted = 0
AND i.companyid = 158
AND incidentno <> 0
--AND reportcompleted = 1
--AND investigatorassignedtime IS NOT NULL
--AND investigatorfinishedtime IS NULL
--AND closedtime IS NULL
),
ic2 AS (
SELECT * FROM ic WHERE rn=1
)
SELECT * FROM ic2
--WHERE rownumber >= 0
-- AND rownumber < 0 + 10
--WHERE ic2.incidentid in(53327,53538)
--WHERE ic2.incidentid = 53338
ORDER BY incidentid DESC
Following is the execution plan I got:
https://www.dropbox.com/s/50dcpelr1ag4blp/Execution_Plan.sqlplan?dl=0
There are several issues:
1) use UNION ALL instead of UNION ALL to avoid the additional operation to aggregate the data.
2) try to modify the numerous function calls (e.g. dbo.Incidentdescription() ) to be an in-lie table valued function so you can reference it using CROSS APPLY or OUTER APPLY. Especially, if those functions referencing a table again.
3) move the subqueries from the SELECT part of the query to the FROM part using CROSS APPLY or OUTER APPLY again.
4) after the above is done, check the execution plan again for any missing indexes. Also, run the query with STATISTICS TIME, IO on to verify that the number of times a table
is referenced is correct (sometimes the execution plan put you in the wrong direction, especially if function calls are involved)...
Since the first inner query produces rows with ord=1 and the second produces rows with ord=2, you should use UNION ALL instead of UNION. UNION will filter out equal rows and since you will never get equal rows it is more efficient to use UNION ALL.
Also, rewrite your query to not use the WITH construct. I've had very bad experiences with this. Just use regular derived tables instead. In the case the query is still abnormally slow, try to serialize some derived tables to a temporary table and query the temporary table instead.
Try alternate approach by removing
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader
from the SELECT. Avoid using complex functions/sub-queries in select.