Sql server SQL Server 2012:在同一个表上同时从SELECT运行多个更新

Sql server SQL Server 2012:在同一个表上同时从SELECT运行多个更新,sql-server,locking,sql-update,Sql Server,Locking,Sql Update,情况: 1) 有大的表1(9GB数据,20GB idx空间,12M行) 2) 在表1上有几个更新和更新/选择,它们逐个运行 3) 每个UPDATE语句更新不同的列 4) 他们都没有使用以前更新的列来计算新更新的列 5) 完成这些需要一段时间 问题: 我想同时运行这些更新,但我担心死锁。如何避免它们设置事务隔离级别READ UNCOMMITTED是否有帮助 更新看起来像: update TABLE1 set col1 = subs.col2 from (select ID, col2 from T

情况:

1) 有大的表1(9GB数据,20GB idx空间,12M行)
2) 在表1上有几个更新更新/选择,它们逐个运行
3) 每个UPDATE语句更新不同的列
4) 他们都没有使用以前更新的列来计算新更新的列
5) 完成这些需要一段时间

问题:

我想同时运行这些更新,但我担心死锁。如何避免它们设置事务隔离级别READ UNCOMMITTED是否有帮助

更新看起来像:

update TABLE1 set col1 = subs.col2
from (select ID, col2 from TABLE2) subs
where TABLE1.ID = subs.ID

update TABLE1 set col10 = col2+col3+col4

update TABLE1 set col100 = col2 + subs.col4
from (
    select 
        b.ID, a.col4
    from 
        TABLE3 a 
        join TABLE1 b on TABLE1.ID2 = TABLE3.ID2
) subs
where TABLE1.ID = subs.ID

update TABLE1 set col1000 = col2+col3+col4
from TABLE1
join TABLE4 on TABLE4.date = TABLE1.date
join TABLE5 on TABLE5.ID3 = TABLE1.ID 

如果相同的列没有更新,也没有在其他子句中使用,则带有readuncommitted的脏读可能会起作用,但我担心这是一个脆弱的解决方案

要获得更一致的解决方案,您可以根据操作将ROWLOCK/UPDLOCK/NOLOCK混合使用。F.e

UPDATE
    TABLE1 WITH (ROWLOCK)
SET
    col1 = TABLE2.col2
FROM
    TABLE1 WITH (ROWLOCK, UPDLOCK)
    INNER JOIN TABLE2 WITH (NOLOCK) ON (TABLE1.ID = TABLE2.ID)
如果您的语句主要更新不同的行,则可以省略ROWLOCK

在极少数情况下,可能会发生锁升级,但它会受到以下限制:

ALTER TABLE TABLE1 SET (LOCK_ESCALATION = DISABLE)
顺便问一下,你的解决方案的目的是什么?我不认为您会赢得很多性能,小部分更新可以比并行处理大更新更快。

(1)在更新时避免子查询。多个子查询可能会快速导致锁升级并导致死锁

(2) 查看下面的讨论


(3) 对于当前的阻塞和锁定,请查看

上的讨论另一种策略:创建一个临时表,其中包含要插入的行的ID以及列的新值

CREATE TABLE #tmp (
  RowID          int,
  NewCol1Value   ...,
  NewCol2Value   ...,
  NewCol2Value   ...
)

-- Insert into the tmp table
...

UPDATE Table1
  SET  Col1 = ISNULL(NewCol1Value, Col1),
       Col2 = ISNULL(NewCol2Value, Col2),
       ...
  FROM Table1 INNER JOIN #tmp ON Table1.RowID = #tmp.RowID

我很感谢您的努力,但是您的解决方案仍然会以死锁告终,因为存在完整的表扫描。如果您在选择子句中使用UPDLOCK,那么scan将获得更新->独占锁。两个线程不能共享它们,所以我认为您不会面临死锁。更新了答案并提供了更多详细信息。关于用途:它的数据仓库数据库和我正在更新的这个特定表是主销售表。每次销售都会计算一些价值(如附加费用/成本)。所以基本上,我运行的几次更新都在更新每一行的大部分内容。那里没有“小更新”。我有v。拥有大量RAM和CPU内核并并行运行查询的强大服务器提高了性能。顺便说一句:我甚至在考虑N个临时表和ETL过程结束时的一个且只有一个大型更新。临时表可能会有所帮助,如果您使用SELECT INTO,与更新相比,这是记录最少的操作之一,记录最多的操作(尤其是在并行更新时,因为如果更改未命中日志缓存,则线程会将相同的记录写入WAL,从而导致更多IO操作)。此外,大型更新的最佳做法是将其拆分为较小的更新。因此,如果您有唯一标识符/时间戳或任何其他范围字段,则最好将12M记录拆分为10K-100K块并相互更新。这些更新是在一个会话中顺序运行还是多个会话将同时执行这些更新?为什么我问这个问题,因为你们提到了ETL过程。通常ETL过程在一个线程中运行。