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?

关于sql server查询的where不识别列名的问题

SQL Server 2005 - WHERE NOT EXISTS 和 NOT EXISTS 内的复杂脚本

sql server 2008 r2:当前会计年度 where 子句中的 case 语句