Sql 存储过程性能改进
请检查下面的Microsoft SQL StoredProcess查询。有了这个问题,我完成这个过程变得非常缓慢。对于仅1000/2000条记录,执行时间超过20秒。现在我的问题是如何调整此查询以提高其性能?我不需要整个工作查询,但我需要专家的建议,我可以做什么来提高其性能?有没有更好的短方法来编写相同的查询?请给我一些建议。提前谢谢 性能差的SQL:Sql 存储过程性能改进,sql,sql-server,Sql,Sql Server,请检查下面的Microsoft SQL StoredProcess查询。有了这个问题,我完成这个过程变得非常缓慢。对于仅1000/2000条记录,执行时间超过20秒。现在我的问题是如何调整此查询以提高其性能?我不需要整个工作查询,但我需要专家的建议,我可以做什么来提高其性能?有没有更好的短方法来编写相同的查询?请给我一些建议。提前谢谢 性能差的SQL: USE [Analytics] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO AL
USE [Analytics]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [vision].[SancusoReferralExceptionsReport]
as
begin
Declare @programid varchar(30) ;
DECLARE @Startdate DATETIME = '1900-01-01'
set @programid = '31';
;
with ProgramExceptions as
(
-- 1. Referring contact name should not be blank
select 'Referral Pharmacy Contact Name should not be blank' as ExceptionReason
, a.AspnRxID
, ap.PrescriptionID
from [ArmadaRX].aspn.ASPNRX a
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = a.AspnRxID
where a.ProgramID in (31)
and (@Startdate is null or (a.CreatedOn between @Startdate and getdate()))
and (a.ReferringPharmacyContact is null or rtrim(ltrim(a.ReferringPharmacyContact)) = '')
union
-- 2. Received/Referral Date should not be blank
select 'Received/Referral date should not be blank' as ExceptionReason
, a.AspnRxID
, ap.PrescriptionID
from [ArmadaRX].aspn.ASPNRX a
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = a.AspnRxID
where a.ProgramID in (31)
and (@Startdate is null or (a.CreatedOn between @Startdate and getdate()))
and a.ReceivedOn is null
) /* end of CTE */
select distinct
pe.ExceptionReason
, pe.AspnRxID
, a.ProgramID
, prg.ProgramName
, coalesce(cp.ReferralType,a.ReferralType) ReferralType
, a.RxType
, a.ProgramStatus
, a.ProgramSubstatus
, a.ReceivedOn as ReceivedOnDate
, a.PrescriptionDate
, ap.FillDate
, ap.ShipDate
, cp.Quantity as PrescriptionQuantity
, ap.FillQty
, ap.Indicator
, a.CreatedOn as CreateDate
, a.ModifiedOn as ModifyDate
, a.AssignedOn as AssignDate
, a.AcceptedOn as AcceptDate
, a.CompletedOn as CompleteDate
, a.CancelledOn as CancelDate
, a.FillingPharmacyContact
, a.ReferringPharmacyContact
, m.MemberName as FillingPharmacyName
, m2.MemberName as ReferringPharmacyName
, cp.PrescriptionID
, cp.DrugName
, cp.Copay as PrescriptionCopay
, a.ReferralCode
, (select [TypeCode] from [ArmadaRX].[common].[INSURANCETYPE] where [InsuranceTypeID] = cp.InsuranceType) as InsuranceType
, cp.InsuranceName
, pd.NPI
, cp.Binnumber
from ProgramExceptions pe
inner join [ArmadaRX].aspn.ASPNRX a on a.AspnRxID = pe.AspnRxID
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = pe.AspnRxID and (pe.PrescriptionID is null or ap.PrescriptionID = pe.PrescriptionID)
left outer join [ArmadaRX].common.PRESCRIPTION cp on cp.PrescriptionID = ap.PrescriptionID and (pe.PrescriptionID is null or cp.PrescriptionID = pe.PrescriptionID)
left outer join ArmadaRX.aspn.PRESCRIPTIONDOCTOR pd on pd.PrescriptionID = cp.PrescriptionID
left outer join [ArmadaRX].common.Patient p on p.patientID = a.PatientID
left outer join [ArmadaRX].aspn.Program prg on prg.ProgramID = a.ProgramID
left outer join ArmadaApproveRx.dbo.vMember m on m.MemberID = a.FillingPharmacyID
left outer join ArmadaApproveRx.dbo.vMember m2 on m2.MemberID = a.ReferringPharmacyID
where a.ProgramID in (31)
order by pe.AspnRxID
end
根据我的经验,对大型数据集使用CTE会降低查询的性能。在将CTE转换为临时表的过程中,我发现性能有了很大的提高,因为这确实使我能够根据需要创建索引。下面的代码是使用CTE将OPs示例查询转换为使用临时表的示例
USE [Analytics]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [vision].[SancusoReferralExceptionsReport]
as
begin
Declare @programid varchar(30) ;
DECLARE @Startdate DATETIME = '1900-01-01'
set @programid = '31';
SELECT *
INTO #TempTable
FROM (
-- 1. Referring contact name should not be blank
select 'Referral Pharmacy Contact Name should not be blank' as ExceptionReason
, a.AspnRxID
, ap.PrescriptionID
from [ArmadaRX].aspn.ASPNRX a
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = a.AspnRxID
where a.ProgramID in (31)
and (@Startdate is null or (a.CreatedOn between @Startdate and getdate()))
and (a.ReferringPharmacyContact is null or rtrim(ltrim(a.ReferringPharmacyContact)) = '')
union
-- 2. Received/Referral Date should not be blank
select 'Received/Referral date should not be blank' as ExceptionReason
, a.AspnRxID
, ap.PrescriptionID
from [ArmadaRX].aspn.ASPNRX a
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = a.AspnRxID
where a.ProgramID in (31)
and (@Startdate is null or (a.CreatedOn between @Startdate and getdate()))
and a.ReceivedOn is null
) AS T
select distinct
pe.ExceptionReason
, pe.AspnRxID
, a.ProgramID
, prg.ProgramName
, coalesce(cp.ReferralType,a.ReferralType) ReferralType
, a.RxType
, a.ProgramStatus
, a.ProgramSubstatus
, a.ReceivedOn as ReceivedOnDate
, a.PrescriptionDate
, ap.FillDate
, ap.ShipDate
, cp.Quantity as PrescriptionQuantity
, ap.FillQty
, ap.Indicator
, a.CreatedOn as CreateDate
, a.ModifiedOn as ModifyDate
, a.AssignedOn as AssignDate
, a.AcceptedOn as AcceptDate
, a.CompletedOn as CompleteDate
, a.CancelledOn as CancelDate
, a.FillingPharmacyContact
, a.ReferringPharmacyContact
, m.MemberName as FillingPharmacyName
, m2.MemberName as ReferringPharmacyName
, cp.PrescriptionID
, cp.DrugName
, cp.Copay as PrescriptionCopay
, a.ReferralCode
, (select [TypeCode] from [ArmadaRX].[common].[INSURANCETYPE] where [InsuranceTypeID] = cp.InsuranceType) as InsuranceType
, cp.InsuranceName
, pd.NPI
, cp.Binnumber
from #TempTable pe
inner join [ArmadaRX].aspn.ASPNRX a on a.AspnRxID = pe.AspnRxID
left outer join [ArmadaRX].aspn.ASPNRX_PRESCRIPTION ap on ap.AspnRxID = pe.AspnRxID and (pe.PrescriptionID is null or ap.PrescriptionID = pe.PrescriptionID)
left outer join [ArmadaRX].common.PRESCRIPTION cp on cp.PrescriptionID = ap.PrescriptionID and (pe.PrescriptionID is null or cp.PrescriptionID = pe.PrescriptionID)
left outer join ArmadaRX.aspn.PRESCRIPTIONDOCTOR pd on pd.PrescriptionID = cp.PrescriptionID
left outer join [ArmadaRX].common.Patient p on p.patientID = a.PatientID
left outer join [ArmadaRX].aspn.Program prg on prg.ProgramID = a.ProgramID
left outer join ArmadaApproveRx.dbo.vMember m on m.MemberID = a.FillingPharmacyID
left outer join ArmadaApproveRx.dbo.vMember m2 on m2.MemberID = a.ReferringPharmacyID
where a.ProgramID in (31)
order by pe.AspnRxID
DROP TABLE #TempTable
end
检查与日期相关的列日期有什么问题?你能详细解释一下吗?我不喜欢保险类型的子选择。您不能将其设置为常规联接吗?
有没有更好的短方法来编写相同的查询?
我们的任务跟踪器中没有包含所有需求和数据模型描述的任务。因此,用任何其他给出相同输出的连接和/或谓词列表重写它,对我们任何人来说都肯定是棘手的。你有实际的执行计划吗?您是否需要所有这些distincts和跨数据库联接?当@Startdate
从不为空时,为什么查询检查@Startdate为空!顺便说一句,这项工作做得很好,但如果您添加一些解释,这将更有帮助。根据我的经验,对大型数据集使用CTE会降低查询的性能。在将CTE转换为临时表的过程中,我发现性能有了很大的提高,因为这确实使我能够根据需要创建索引。上面的代码是使用CTE将OPs示例查询转换为使用临时表的示例。