SQL Server - 当 WHERE 原因是唯一 ID 时进行多次更新的最有效方法
Posted
技术标签:
【中文标题】SQL Server - 当 WHERE 原因是唯一 ID 时进行多次更新的最有效方法【英文标题】:SQL Server - Most efficient way to do multiple updates when WHERE cause is a unique ID 【发布时间】:2020-04-06 15:16:20 【问题描述】:假设我在 SQL Server 数据中有 10-20k 条记录要更新,我需要执行以下操作:-
UPDATE dbo.MyTable SET Field1 = 95 WHERE MyTableID = 348923
UPDATE dbo.MyTable SET Field1 = 90 WHERE MyTableID = 348924
UPDATE dbo.MyTable SET Field1 = 100 WHERE MyTableID = 348925
MyTableID 是主键,因此保证每次都不同。我想知道运行这个最有效的方法是什么,当你开始连续使用 10k 到 20k 甚至更多的 UPDATE 语句时,因为我已经读过每个 UPDATE 都是对该表的查找,这已经很大了。
我考虑过并且知道:-
光标(目前看起来更可取) 如上所述的单一更新列表,只需处理缓慢谁能建议最有效的方法是什么?
谢谢。
【问题讨论】:
【参考方案1】:运行多个查询可能是一种有效的方法,因为它可以利用主键索引。
您也可以尝试使用条件表达式,例如:
UPDATE dbo.MyTable
SET Field1 = case MyTableID
WHEN 348923 HEN 95
WHEN 348924 THEN 90
WHEN 348924 THEN 100
END
WHERE MyTableID IN (348923, 348924, 348925)
如果要更新的 id 列表确实在范围内,WHERE
子句可以按以下形式优化,这将利用索引:
WHERE MyTableID BETWEEN 348923 AND 348925
【讨论】:
【参考方案2】:在 SQL Server 中,我推荐JOIN
:
UPDATE t
SET Field1 = v.Field1
FROM dbo.MyTable t JOIN
(VALUES (95, 348923),
(90, 348924),
(100, 348925)
) v(Field1, MyTableId)
ON v.MyTableId = t.MyTableId;
这应该与使用CASE
具有基本相同的性能。我觉得更容易管理。如果你想设置多列,那就更简单了。
【讨论】:
【参考方案3】:准备一个脚本模板,通过创建如下表变量来处理更新
declare @your_tbl_name table
MyTableID int,
Field1 int
将所有值插入此表变量
insert into @your_tbl_name
select Field1,MyTableID from your [actualsource]
将此表变量与实际表进行内连接并更新值。
update t
set t.Field1 = tbl.Field1
from dbo.MyTable t
inner join @your_tbl_name tbl
on t.MyTableID = tbl.MyTableID
【讨论】:
【参考方案4】:我认为 Gordon Linoff 提供了一个很好的方法。 要确定这是否可行,您需要即时更新还是可以批量更新?
如果您可以批量处理它们,请考虑更新需要多久反映一次主表。 您可能会更幸运地将所有更改添加到临时表中,然后再运行更新。这实际上取决于您需要的性能,以及您今天的性能。如果您有一堆个人用户同时运行更新,并且每个用户都需要能够立即更新单独的数据,那么需要考虑不同的方法。但是,如果您只能经常处理这些值的更新,请批量处理它们!我从向我公司出售产品的公司那里收到了大量更新,这是我必须采取的提高效率的途径。
如果您可以使用暂存表,这就是该批次的外观。
--Creates a staging table
create table dbo.StageUpdates
(
ID int primary key
, NewValue int
)
--Adds values to update to staging table
insert into dbo.StageUpdates
VALUES
(348923, 95)
,(348924, 90)
,(348925, 100)
--Update values
update dbo.MyTable
set Field1 = NewValue
from dbo.MyTable as mt
inner join dbo.StageUpdates as su on mt.ID = su.ID
where su.NewValue <> mt.Field1 --Modify this if either value can be null.
--Clear updated values from stage
delete from dbo.StageUpdates
from dbo.StageUpdates as su
inner join dbo.MyTable as mt on su.ID = mt.ID
where su.NewValue <> mt.Field1 --Modify this if either value can be null.
【讨论】:
以上是关于SQL Server - 当 WHERE 原因是唯一 ID 时进行多次更新的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章
为啥当 WHERE 子句包含参数化值时 SQL Server 使用索引扫描而不是索引查找
当 WHERE 子句中只有一列时,SQL Server 会使用复合索引吗?
为啥当我的查询有 Where 时 SQL Server 有更多的 I/O?