我在表的更新触发器中有一个查询(见下文),并根据触发器中当前更新的内容更新大型数据集上的某些字段。对于一组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:表格红色包含超过数万亿条记录
答案 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
替换IN
和EXISTS
。 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甚至可以建议可以加速查询的索引。