提高SQL Server存储过程的性能

时间:2015-11-04 14:37:12

标签: sql-server stored-procedures

我需要提高SSRS使用的存储过程的性能。当传递一组非常窄的参数时,存储过程会很快完成。但是当返回超过十万个结果时,存储过程需要几分钟才能运行。

例如,如果我使用1982年到2020年的日期范围运行它,则需要15分钟才能运行并返回180000条记录。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[uspContractFundingbyYear2]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[uspContractFundingbyYear2]
GO

-- =============================================
-- Author:      J. Dickens
-- Create date: April 2011
-- Description: This SP generates contract funding records for the selected parameters.
--              Each row should represent a single contract funding record. 
--              In many cases, either 0 or 100 is used to designate an option that is not selected. The parameter should have no impact on the query. 
--              Otherwise all values are passed to the parameter using the multivalue parameter function.
-- =============================================

CREATE PROCEDURE [dbo].[uspContractFundingbyYear2]
    @StartYear datetime
    ,@EndYear datetime
    ,@BusinessEntityID  nvarchar(max)
    ,@ContractTypeCode nvarchar(max)
    ,@ContractStatusCode nvarchar(max)
    ,@ContractOrgID nvarchar(max)
    ,@ResearchTypeCode nvarchar(max)
    ,@ExportControlLevelCode nvarchar(max)
    ,@ScienceAreaID nvarchar(max)
    ,@ThrustAreaID nvarchar (max)
    ,@ContractStartdate datetime
    ,@ContractEnddate datetime
    ,@ResearchBusID int
    ,@MasterContractOnlyFlag bit
    ,@StateProvinceCode nvarchar(max)
    ,@CountryID nvarchar(max)
    ,@FinalYearFlag int
    ,@CollaborativeDollars int
    ,@SubcontractsFlag int
    ,@FundingOrgID nvarchar(max)
    ,@FundingTypeCode nvarchar(max)
    ,@FundingStatusCode nvarchar(max)
    ,@FundingStartdate datetime
    ,@FundingEnddate datetime
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    --- Prepare a table of Year Numbers, for use with Cross Join
    DECLARE @Dates TABLE (YearNo INT) 

    ;WITH n(n) AS
    (
        SELECT YEAR(@StartYear)
        UNION ALL

        SELECT n+1 
        FROM n 
        WHERE n < YEAR(@EndYear)
    )
    INSERT INTO @Dates(YearNo)
        SELECT n 
        FROM n 
        ORDER BY n

    -- Now find all the contract funding records 
    select distinct
        be.BusinessEntityName 
        , Q.ScienceArea
        , r.ResearchBusID
        , c.FormattedBusID
        , o.Abbreviation as 'ContractOrg'
        , c.StateProvinceCode
        , cy.CountryName
        , cf.ContractFundingID
        , c.ContractTypeCode
        , c.ContractID,
        , [Thrust] = dbo.ufConcatenateThrustsforResTaskDate (r.ResearchID, NULL, NULL, NULL)
        , [PI] = (select STUFF((select distinct(coalesce('; '+P.lastfirst,''))
    from ResTaskParticipant rtp
    join PersonOrg po on rtp.PersonOrgID = po.PersonOrgID
    join Person p on po.PersonID = p.PersonID
    where rtp.ResearchID = r.researchid
      and rtp.ParticipantTypeCode = 'PI'
      and (rtp.enddate > getdate() or rtp.enddate = r.enddate)
    for XML path ('')),1,2,'')),
c.ContractStatusCode,
cf.Fundingstatuscode as 'FundingStatus', cf.FundingTypeCode as 'FundingType', cf.Funding, 
o2.Abbreviation as 'FundingSourceOrg',  cf.StartDate, cf.EndDate,
DATEDIFF(m,cf.StartDate, dateadd(d,2,cf.EndDate)) as 'ContractMonths', --using 2 days here to allow for leap years
[BurnRate] =
case  
when DATEDIFF(m,cf.StartDate, dateadd(d,2,cf.EndDate))  = 0 --using 2 days here to allow for leap years
then convert(decimal(2,1), 0)
else
 convert(decimal (15,5), convert(decimal(15,0),cf.Funding)/convert(decimal(2,0),(DATEDIFF(m,cf.StartDate, dateadd(d,2,cf.EndDate)))))  --using 2 days here to allow for leap years
end
, [IsFirstOfMonth] = 
case when  cf.startdate = (select FirstDayofMonth from dbo.ufGetFirstLastDayofMonth(cf.StartDate, 0)) then 1 else 0 end
, [IsEndOfMonth] = 
case when  datepart(day,cf.EndDate) = datepart(day,(select LastDayofMonth from dbo.ufGetFirstLastDayofMonth(cf.EndDate, 0))) then 1 else 0 end
, [MonthsInYear] = Convert(decimal(2,0), (select dbo.ufmonthsincontractforyear (cf.startdate, cf.EndDate, d.YearNo)))
,[YearNo] =  d.YearNo


from ContractFunding cf 
join Contract c  on cf.ContractID = c.ContractID
join Research r on c.ResearchID = r.ResearchID
join BusinessEntity be on r.BusinessEntityID = be.BusinessEntityID
join Organization o on c.OrganizationID = o.OrganizationID --Contract Org
join Country cy on c.CountryID = cy.CountryID  
join Organization o2 on cf.SourceOrganizationID = o2.OrganizationID --Funding Org
left outer join TaskFunding tf on cf.ContractFundingID = tf.ContractFundingID

--Get the range of years for each Contract Funding row
cross join @Dates d 

--get Science Area
cross apply (select [ScienceArea]  = dbo.ufConcatenateScienceAreasforResTaskDate (r.ResearchID, NULL, NULL, NULL)) as  Q


where
-- required parameters for running report are Start and End Years
cf.StartDate <= @EndYear and cf.EndDate >= @StartYear

-- now all the bells and whistles
and r.BusinessEntityID in (select val from [dbo].[ufStringToTable] (@BusinessEntityID,',',1))
and c.ContractTypeCode in (select val from [dbo].[ufStringToTable] (@ContractTypeCode,',',1))
and c.ContractStatusCode in (select val from [dbo].[ufStringToTable] (@ContractStatusCode,',',1))
and c.OrganizationID in (select val from dbo.ufStringToTable (@ContractOrgID,',',1))
and (@ResearchTypeCode = '0' or (r.ResearchTypeCode in (select val from dbo.ufStringToTable (@ResearchTypeCode,',',1))))
and (@ExportControlLevelCode = '100' or c.ExportControlLevelCode = @ExportControlLevelCode)

-- For Science Area Funding, of the set of Contract Funding records returned, select those that match the given Science Area
and (@ScienceAreaID = '0' or (cf.ScienceAreaID in (select val from dbo.ufStringToTable (@ScienceAreaID,',',1)))) 

-- For Thrust Area Funding, of the set of Contract Funding records returned, select those that match the given Thrust Area
and (@ThrustAreaID = '0' or (tf.ThrustAreaID in (select val from dbo.ufStringToTable (@ThrustAreaID,',',1))))

-- Find Contracts within given "Active" dates
and (
        (@ContractStartdate is null and @ContractEnddate is null)
        OR
        (c.enddate > @ContractStartdate and c.StartDate <=@ContractEnddate)
        or
        (@ContractStartdate is null and c.StartDate <=@ContractEnddate)
        or
        (c.EndDate > @ContractStartdate and @ContractEnddate is null)
    )
and (@ResearchBusID = '' or r.ResearchBusID = @ResearchBusID)
and (@MasterContractOnlyFlag = 0  or (@MasterContractOnlyFlag = 1 and c.MasterContractFlag = 1))
and (@StateProvinceCode = '0' or (c.StateProvinceCode in (select val from dbo.ufStringToTable (@StateProvinceCode,',',1))))

and c.CountryID in (select val from dbo.ufStringToTable (@CountryID,',',1)) --Not all contracts have a country assignment
and (@FinalYearFlag = 100 
    or 
    (@FinalYearFlag = 0 and (dbo.ufContractIsInFinalYear(c.contractid,getdate()) = 0))
    or
    (@FinalYearFlag = 1 and (dbo.ufContractIsInFinalYear(c.contractid,GETDATE()) = 1))
    )

and (@CollaborativeDollars = 100
    or 
    (@CollaborativeDollars = 0 and 
        not exists 
            (select * from ContractFunding cf2 where cf2.FundingTypeCode='Collaborative' and cf2.ContractID=c.ContractID)
        )
    or 
    (@CollaborativeDollars = 1 and 
        exists 
            (select * from ContractFunding cf2 where cf2.FundingTypeCode='Collaborative' and cf2.ContractID=c.ContractID)
        )
    )
and (@SubcontractsFlag = 100
    or 
    (@SubcontractsFlag = 0 and c.SubContractFlag = 0)
    or
    (@SubcontractsFlag = 1 and c.SubContractFlag = 1)
    )

and (cf.SourceOrganizationID in (select val from dbo.ufStringToTable (@FundingOrgID,',',1)))

and (cf.FundingTypeCode in (select val from dbo.ufStringToTable (@FundingTypeCode,',',1)))

and (cf.FundingStatusCode in (select val from dbo.ufStringToTable (@FundingStatusCode,',',1)))
and (
        (@FundingStartdate is null and @FundingEnddate is null)
        OR
        (c.enddate > @FundingStartdate and c.StartDate <=@FundingEnddate)
        or
        (@FundingStartdate is null and c.StartDate <=@FundingEnddate)
        or
        (c.EndDate > @FundingStartdate and @FundingEnddate is null)
    )


End
GO

0 个答案:

没有答案