优化SQL Server 2008中的大型数据集的更新查询

时间:2015-08-28 13:09:49

标签: sql-server sql-server-2008

我在表的更新触发器中有一个查询(见下文),并根据触发器中当前更新的内容更新大型数据集上的某些字段。对于一组100000条记录,大约需要22秒,我想更优化这个

update RED
set EDR_IsLock = @il
where RED.docid in 
      (select a.DocID
       from 
           (select distinct DocID 
            from UVD
            where UVD.UVID in (select i.UVID from inserted i)) a 
       left outer join
           (select distinct UVD.DocID 
            from UVD
            inner join UVH on UVD.UVID = UVH.UVID 
            where UVD.UVID not in (select i.UVID from inserted i) 
              and UVH.IsLock = 1) b on a.DocID = b.DocID
       where b.DocID is null) 

PS:表格红色包含超过数万亿条记录

2 个答案:

答案 0 :(得分:3)

尝试加入而不是in子句。尝试下面的一个,它可能会帮助你。

Update  r
Set     EDR_IsLock = @il
From    RED As r
        Join
        (
            Select  a.DocID
            From    (   Select  Distinct DocID 
                        From    UVD
                                Join inserted i On UVD.UVID = i.UVID
                    ) a 
                    left outer join
                    (
                        Select  Distinct 
                                UVD.DocID 
                        From    UVD
                                join UVH on UVD.UVID = UVH.UVID 
                        Where   UVD.UVID Not In (Select i.UVID From inserted i)
                                And UVH.IsLock = 1
                    ) b on a.DocID = b.DocID
            Where   b.DocID is null
        ) As t On r.docid = t.DocID

<强>更新

我不是一个好的解释者,但是,如果&#34; Not Exists&#34;取而代之的是#34;在Clause&#34;中,我会重写上面的查询,如下所示:

Set Nocount On;

Declare @UVD Table
(
    DocID           Int
)

Declare @UVDWithUVH Table
(
    DocID           Int
)

Insert Into @UVD(DocID)
Select  Distinct 
        DocID 
From    UVD As u With (Nolock)
        Join inserted i On u.UVID = i.UVID

Insert Into @UVDWithUVH(DocID)
Select  Distinct
        u.DocID 
From    UVD As u With (Nolock)
        Join UVH As uh With (Nolock) on u.UVID = uh.UVID 
Where   Not Exists (Select 1 From inserted As i Where i.UVID = u.UVID)
        And uh.IsLock = 1

Update  r
Set     EDR_IsLock = @il
From    RED As r
        Join
        (
            Select  a.DocID
            From    @UVD As a
                    Left Outer Join @UVDWithUVH As b On a.DocID = b.DocID
            Where   b.DocID Is Null
        ) As t On r.docid = t.DocID

在这个解决方案中,我建议使用@Table变量,它将驻留在Ram而不是物理存储中。并且在加入时删除在内部查询内查询不同的开销。

也请尝试更新,并且想知道,它是否有助于提高触发器的性能。

答案 1 :(得分:3)

我个人会将其重写为:

UPDATE  RED
SET     EDR_IsLock = @il
WHERE   RED.DocID IN
        (   SELECT  UVD.DocID
            FROM    UVD
            WHERE   RED.DocID = UVD.DocID
            AND     NOT EXISTS (SELECT 1 FROM inserted i WHERE i.UVID = UVD.UVID)
            AND     NOT EXISTS
                    (   SELECT  UVD.DocID
                        FROM    UVD AS UVD2
                        WHERE   UVD2.DocID = UVD.DocID
                        AND     EXISTS (SELECT 1 FROM UVH WHERE UVH.UVID = UVD2.UVID AND UVH.IsLock = 1)
                        AND     NOT EXISTS (SELECT 1 FROM inserted i WHERE i.UVID = UVD2.UVID)
                    )
        );

在所有情况下,我都会使用JOIN替换INEXISTS。 SQL Server在使用LEFT JOIN/IS NULL删除记录方面存在问题,如documented here,在最佳情况下,您将获得与NOT EXISTS相同的效果,但有时LEFT JOIN将是LEFT JOIN/IS NULL更差。 EXISTS无法使用反半连接(一旦找到一条记录就会停止搜索/扫描),方式UVD也是如此。使用当前的方法,您选择全部来自a的符合条件的记录,然后对它们进行排序,以便删除重复项,然后使用这些结果丢弃子查询INNER JOIN中找到的记录。

类似的逻辑适用于EXISTS,在替换为UVH时,您告诉SQL Server您不关心NOT IN中的记录是什么,您只关心有之一。

我真正做的唯一其他更改是将NOT EXISTS更改为NOT IN,这可能无效,但如果NULL记录$url = 'https://lh6.googleusercontent.com/-T4v5svsA3JU/Tc7jEchmSYI/AAAAAAABAb8/MLXlXjKUyIg/s1024/Dies09_080509_5144.JPG'; $file = file_get_contents($url); $im = imagecreatefromstring($file); $im = imagescale($im, 250); header('Content-Type: image/jpg'); imagejpeg($im); 会导致意外行为在场。

进行这些更改后,您应该运行查询,并显示实际的执行计划。这将有助于识别瓶颈,SQL Server甚至可以建议可以加速查询的索引。