为什么ad-hoc SQL比在存储过程中执行相同的代码运行得更快?

Int*_*eer -1 t-sql sql-server

我有一个存储过程,可以在SQL Server 2005中批量处理电话和地址

如果我执行存储过程需要2个小时.但是,如果我运行相同的代码和相同的批处理,它需要2秒.

我已尝试以下步骤使其更快但它们没有工作:

  • 重新索引整个数据库
  • SET ANSI_NULLS ON;
  • DBCC FreeProcCache
  • DBCC DROPCLEANBUFFERS

这是基本代码

USE [MyDB]

GO



/****** Object:  StoredProcedure [myschema].[ProccesBatch]    Script Date: 06/30/2011 10:37:33 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE [myschema].[ProccesBatch] 
-- Add the parameters for the stored procedure here

(@BatchId int)


AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.

SET NOCOUNT ON;
SET ANSI_NULLS ON;

-- AD Hoc TESTING ONLY. This gets uncommented when running ad hoc.
-- DECLARE @BatchId Int
-- SET @BatchId = 59

DECLARE @MyList AS VARCHAR (500)
DECLARE @MySICList AS VARCHAR (500)
DECLARE @MyType AS CHAR (1)
DECLARE @MyProvider AS VARCHAR (500)
DECLARE @MyState AS VARCHAR (2)
DECLARE @MyCityList AS VARCHAR (500)
DECLARE @MyZipList AS VARCHAR (500)
DECLARE @MyStyle AS VARCHAR (1)
DECLARE @MySource AS VARCHAR (150)
DECLARE @MyStartDate AS DATETIME
DECLARE @MyEndDate AS DATETIME
DECLARE @MyCampaign  AS BIT
DECLARE @CheckExist AS INT
SET @CheckExist = 0
-- 
--  1. Check if Campaign Exist.
--  
SELECT 
    @CheckExist = Id 
FROM myschema.Destination
WHERE Id = @BatchId

IF @CheckExist > 0
     BEGIN
     RAISERROR('Creation has already been processed', 16, 1)
     RETURN
     END      

-- 
--  2. Get Header and parameters for controlling process.
-- 
SELECT       
    @MyList = ISNULL(LeadBatchHeaderList,''),       
    @MySICList = ISNULL(SICCodeList,''),
    @MyType = ISNULL(MyType,''),
    @MyProvider = ISNULL(LDCList,''),
    @MyState = ISNULL([State],''),
    @MyCityList = ISNULL(CityList,''),      
    @MyZipList = ISNULL(ZipCodeList,''),        
    @MyStyle = ISNULL(Commodities,''),
    @MySource = ISNULL(LeadSource,''),
    @MyStartDate = ISNULL(HeaderCreationStart,''),
    @MyEndDate = ISNULL(HeaderCreationEnd,''),
    @MyCampaign = ISNULL(AllCampaign ,'')
FROM myschema.Header
WHERE ID = @BatchId

IF @@ROWCOUNT < 1
     BEGIN
     RAISERROR('header id was not found', 16, 1)
     RETURN
     END   

-- Place Commas for charindex     
IF @MyList > ''
    SET @MyList = ',' + @MyList + ','
IF @MySICList  > ''
    SET @MySICList =  ',' + @MySICList + ','
IF @MyProvider > ''
    SET @MyProvider = ',' + @MyProvider + ','
IF @MyCityList > '' 
    SET @MyCityList = ',' + @MyCityList + ','   
IF @MyZipList > '' 
    SET @MyZipList = ',' + @MyZipList + ','    

--
-- 3. Add  qualifying leads.
--
INSERT INTO myschema.Destination    
(Id, LeadBatchDetailId, CustomerIdOne, CustomerIdTwo, MyProviderOne, MyProviderTwo, SicCode, SicDesc, SicCode2, SicDesc2, 
MyType, Company, CompanyURL, Title, Salutation, Suffix, FullName, FirstName, MiddleInitial, 
LastName, Email, MyPhone, Work, Cell, Home, Fax, Ext, Address1, Address2, City, [State], 
Zip5, Zip4, County, TSR, EmployeeSize, Revenue, MyProviderOne, MyProviderTwo, CustomerUsageOne, CustomerUsageTwo, MyExpenses, Remarks, Decline, 
WhyLeft, PCC, RCC, PCC, SCC)
SELECT 
    @BatchId, d.ID, d.CustomerIdOne, d.CustomerIdTwo, d.MyProviderOne, d.MyProviderTwo, d.SicCode, d.SicDesc, d.SicCode2, d.SicDesc2, 
    d.MyType, d.Company, d.CompanyURL, d.Title, d.Salutation, d.Suffix, d.FullName, d.FirstName, d.MiddleInitial, 
    d.LastName, d.Email, d.MyPhone, d.Work, d.Cell, d.Home, d.Fax, d.Ext, d.Address1, d.Address2, d.City, d.[State], 
    d.Zip5, d.Zip4, d.County, d.TSR, d.EmployeeSize, d.Revenue, d.MyProviderOne, d.MyProviderTwo,d.CustomerUsageOne, d.CustomerUsageTwo, d.MyExpenses, d.Remarks, d.Decline, 
    d.WhyLeft, d.PCC, d.RCC, d.PCC, d.SCC
FROM myschema.Source as d 
JOIN myschema.Summary as h ON d.MyId = h.ID
JOIN myschema.source AS s ON h.Id = s.ID
WHERE
    -- MyId. 
    (@MyList = '' OR (charindex(',' + CAST(d.MyId AS VARCHAR) + ',', @MyList) > 0)) AND

    -- SIC Code. 
    (@MySICList = '' OR (charindex(',' + CAST(d.SicCode AS VARCHAR) + ',', @MySICList) > 0)) AND

    -- My Types 
    (@MyType = '' OR @MyType = 'A' OR d.MyType = @MyType OR h.DefaultMyType = @MyType) AND

    -- MYProviders
    ((@MyProvider = '' OR (charindex(',' + CAST(d.MyProviderOne AS VARCHAR) + ',', @MyProvider) > 0)) OR
    (@MyProvider = '' OR (charindex(',' + CAST(d.MyProviderTwo AS VARCHAR) + ',', @MyProvider) > 0))) AND

    -- State. 
    (@MyState = '' OR d.[State] = @MyState) AND

    -- City.
    (@MyCityList = '' OR (charindex(',' + d.City + ',', @MyCityList) > 0)) AND

    -- Zip Code. 
    (@MyZipList = '' OR (charindex(',' + d.Zip5 + ',', @MyZipList) > 0)) AND

    -- LeadSource
    (@MySource = '' OR s.MySource = @MySource) AND

    -- Between Dates
    (@MyStartDate = '' AND @MyEndDate = '' OR h.CreationDate BETWEEN @MyStartDate AND @MyEndDate) AND 

     -- Mystyle
    ((@MyStyle = 'A' AND (d.MyProviderOne IS NOT NULL OR d.MyProviderOne > 0 OR d.CustomerUsageOne > 0)) OR
    (@MyStyle = 'B' AND (d.MyProviderTwo IS NOT NULL OR d.MyProviderTwo > 0 OR d.CustomerUsageTwo > 0)) OR
    (@MyStyle = '' OR @MyStyle IS NULL)) AND

    -- Source parameters are important. Only processed finished batches.
    (h.UseThisRecord = 1) AND
    (h.[status] = 'Finished') AND
    (d.MyDuplicate IS NULL) AND
    (d.DoNotUseFlag IS NULL) AND
    (d.DoNotUseIFlag IS NULL) AND
    (d.CustomerHome IS NULL) AND
    (d.CustomerWork IS NULL) AND
    (d.LeadDuplicate IS NULL) AND
    (d.MyPhone >'' OR d.MyPhone <> NULL) AND
    ((CAST(FLOOR( CAST( h.ExpirationDate AS FLOAT ) )AS DATETIME) > CAST(FLOOR( CAST( GETDATE() AS FLOAT ) )AS DATETIME)) OR 
    h.ExpirationDate IS NULL)



--
-- 4. Flag Phone Duplicates inside myschema.Destination
--

 UPDATE T1
  SET DeleteFlag = 1
  FROM myschema.Destination T1, myschema.Destination T2
  WHERE
        T1.MyPhone = T2.MyPhone AND                   
        T1.FullName = T2.FullName AND 
        T1.Address1 = T2.Address1 AND       
        T1.City = T2.City AND                     
        T1.[State] = T2.[State] AND                     
        T1.Zip5 = T2.Zip5 AND                     
        T1.MyPhone <> '' AND
        T1.Id = T2.Id AND -- This will flag the batch itself
        T1.Id = @BatchId AND
        T1.Id < T2.Id  -- This will leave the highest Id unflagged (latest record) 



--
-- 5. Duplicate Contact Flag. All Records
--      
IF @MyCampaign  = 1
UPDATE T1
  SET DeleteFlag = 1
  FROM myschema.Destination T1, myschema.Destination T2
  WHERE
        T1.MyPhone = T2.MyPhone AND                   
        T1.FullName = T2.FullName AND 
        T1.Address1 = T2.Address1 AND       
        T1.City = T2.City AND                     
        T1.[State] = T2.[State] AND                     
        T1.Zip5 = T2.Zip5 AND                     
        T1.MyPhone <> '' AND
        T1.Id = @BatchId AND
        T1.Id <> T2.Id -- Process against other batches



--
-- 6. Active Flag
--  

IF @MyCampaign <> 1
UPDATE T1
  SET DeleteFlag = 1
  FROM myschema.Destination T1, myschema.Destination T2
  JOIN myschema.Header H ON T2.Id = H.ID
  WHERE
        T1.MyPhone = T2.MyPhone AND                   
        T1.FullName = T2.FullName AND 
        T1.Address1 = T2.Address1 AND       
        T1.City = T2.City AND                     
        T1.[State] = T2.[State] AND                     
        T1.Zip5 = T2.Zip5 AND                     
        T1.MyPhone <> '' AND
        T1.Id = @BatchId AND
        T1.Id <> T2.Id AND -- Process against other batches
        H.ActiveBatch = 1 -- Only Active



--
-- 7. Delete DeleteFlag rows. Check for Id just in case
--  
IF @BatchId > 0
    DELETE FROM myschema.Destination
        WHERE        
            (DeleteFlag = 1) AND (Id = @BatchId)



--
-- 8. Update header with date last run
--                  
UPDATE myschema.Header
SET DateLastRun = GETDATE()
WHERE ID = @BatchId



END






GO
Run Code Online (Sandbox Code Playgroud)

谢谢,克里斯蒂安

gbn*_*gbn 5

当您在proc和常量ad-hoc中使用参数时,通常会发生这种情况

SQL Server通常尝试生成可重用的计划.使用常量它不需要,因为它永远不能重复用于不同的常量.

还有其他选项,例如存储过程的SET选项或数据类型不匹配..但我们没有进一步的信息.