SQL Merge - 如何优化它?

时间:2013-12-12 21:47:57

标签: sql sql-server query-optimization sql-optimization sql-merge

表A(要合并的表)有90,000行 表B(源表)有3,677行 我希望这个合并得非常快,但需要花费30分钟(并计算)。 如何优化以更快地运行?

ALTER PROCEDURE [dbo].[MergeAddressFromGraph] 
-- no params

AS 开始      - 添加SET NOCOUNT ON以防止出现额外的结果集      - 干扰SELECT语句。     SET NOCOUNT ON;

-- first add fids to the MergeFundraiserNameAddress table instead of the temp table?

SELECT fundraiserid, ein
INTO #fids 
FROM  bb02_fundraiser

BEGIN TRAN;
MERGE BB02_FundraiserNameAddress AS T
USING
(    
    select f.fundraiserid,
           n.addresslines,
           n.town,
           n.county,
           n.postcode,
           n.country,
           n.fulladdress,
           n.ein
    from MergeFundraiserNameAddress n
         join bb02_fundraiser f
         on f.ein = n.ein and f.isdefault = 1
    group by n.ein,
             f.fundraiserid,
             n.addresslines,
             n.town,
             n.county,
             n.postcode,
             n.country,
             n.fulladdress

) AS S
ON (T.fundraiserid in( (select fundraiserid from #fids where ein = S.ein)) )

WHEN MATCHED
    THEN UPDATE
        SET    
              -- ADDRESS
              T.addresslines = S.addresslines
              ,T.town = S.town
              ,T.county = S.county
              ,T.postcode = S.postcode
              ,T.country = S.country
              ,T.fulladdress = S.fulladdress

;

DELETE FROM MergeFundraiserNameAddress

COMMIT TRAN;

drop table #fids

END

更新 我能够改进现在只需几秒钟即可运行的存储过程。我加入了临时表而不是bb02_fundraiser表,并删除了ON子句中的子查询。

我现在意识到Merge不是必需的,我可以使用Update,但我现在对此很好,因为在重构中可能很快就需要INSERT。

以下更新的存储过程 IF OBJECT_ID('tempdb .. #fids')IS NOT NULL     DROP TABLE #fids

SELECT fundraiserid, ein
INTO #fids 
FROM  bb02_fundraiser
where isdefault = 1

BEGIN TRAN;
MERGE BB02_FundraiserNameAddress AS T
USING
(    
    select f.fundraiserid,
           n.addresslines,
           n.town,
           n.county,
           n.postcode,
           n.country,
           n.fulladdress,
           n.ein
    from MergeFundraiserNameAddress n
         join #fids f
         on f.ein = n.ein
    group by n.ein,
             f.fundraiserid,
             n.addresslines,
             n.town,
             n.county,
             n.postcode,
             n.country,
             n.fulladdress

) AS S
ON (T.fundraiserid = S.fundraiserid)

WHEN MATCHED
    THEN UPDATE
        SET    
              -- ADDRESS
              T.addresslines = S.addresslines
              ,T.town = S.town
              ,T.county = S.county
              ,T.postcode = S.postcode
              ,T.country = S.country
              ,T.fulladdress = S.fulladdress

;

DELETE FROM MergeFundraiserNameAddress

COMMIT TRAN;

IF OBJECT_ID('tempdb..#fids') IS NOT NULL
DROP TABLE #fids

2 个答案:

答案 0 :(得分:0)

如果只有这份声明为你完成这项工作,请参见下文。

UPDATE T
SET    T.addresslines = n.addresslines
      ,T.town = n.town
      ,T.county = n.county
      ,T.postcode = n.postcode
      ,T.country = n.country
      ,T.fulladdress = n.fulladdress
    from MergeFundraiserNameAddress n join bb02_fundraiser f
    on f.ein = n.ein and f.isdefault = 1
    INNER JOIN  BB02_FundraiserNameAddress T
    ON T.fundraiserid = f.fundraiserid AND T.ein = f.ein
group by n.ein,
             f.fundraiserid,
             n.addresslines,
             n.town,
             n.county,
             n.postcode,
             n.country,
             n.fulladdress

正如其他用户在您的评论中提到的,为什么在仅更新记录时使用MERGE语句。当您执行多个操作(如UPDATE,DELETE和INSERT)时,将使用MERGE语句。

由于您只是UPDATING记录,因此不需要merge语句。

效果不佳的原因

由于您获取Temp表中的所有记录,然后将其与其他表连接而不在该Temp表上创建任何索引,因此缺少任何索引都会损害查询性能。

当您执行SELECT * INTO #TempTable FROM Some_Table时,它会将Some_Table中的所有数据带入Temp表而不是索引。你可以通过运行这个简单的查询来看到自己

select * from tempdb.sys.indexes
where object_id = (select object_id 
                   from tempdb.sys.objects 
                   where name LIKE '#TempTable%')

答案 1 :(得分:0)

也可以在截断时删除原因。

截断表MergeFundraiserNameAddress