如果在更新或删除之前存在?

1 sql-server delete ddl update sql-server-2016

  1. 在写更新语句之前,我应该检查它是否存在吗?

    有人告诉我这样做

    1. 所以它避免了无用的写入事务日志中已经存在的值,

    2. 并且只需要一个允许其他读取的共享锁而不是一个排他锁。
      他们说想象一个事务像这样针对不同的值多次运行,你会一直使用排他锁而不是共享锁。

    3. 同事提到,看锁兼容性图表,搜索时不能有两个更新锁,但可以有两个共享锁。因此,当“搜索要更新的行”没有要更新的值时,假更新锁可以阻止真正的更新。有人可以使此声明无效吗?

      if not exists 
      (
          select FavoriteColor 
          from dbo.Person 
          where Name = 'Bob' 
          and FavoriteColor = 'Green'
      )
      update dbo.Person
      set FavoriteColor = 'Green'
      where Name = 'Bob'
      
      Run Code Online (Sandbox Code Playgroud)
  2. 同样的问题,除了现在删除,我应该检查它是否存在吗?

    if exists 
    (
        select FavoriteColor 
        from dbo.Person 
        where Name = 'Bob' 
        and FavoriteColor = 'Green'
    )
    delete dbo.Person
    where Name = 'Bob' and FavoriteColor = 'Green'
    
    Run Code Online (Sandbox Code Playgroud)

我们使用 SQL Server 2016。

Aar*_*and 6

通常,这种模式更有效,并且不太可能导致死锁或其他并发问题:

UPDATE dbo.Person
  SET FavoriteColor = 'Green'
  WHERE Name = 'Bob'
  AND COALESCE(FavoriteColor, '') <> 'Green';

DELETE dbo.Person
  WHERE Name = 'Bob' 
  AND FavoriteColor = 'Green';
Run Code Online (Sandbox Code Playgroud)

...只是因为您只需检查该行一次。你也可以这样写UPDATE

UPDATE dbo.Person
  SET FavoriteColor = 'Green'
  WHERE Name = 'Bob'
  AND (FavoriteColor IS NULL OR FavoriteColor <> 'Green');
Run Code Online (Sandbox Code Playgroud)

...在某些情况下可能对索引更友好。

直到要修改的行实际更新之前,才会使用写操作的排他锁。当 SQL Server搜索要更新的行时,它使用更新锁,这与并发读取不冲突。如果 SQL Server 确定正在检查的行不符合更新条件,则会立即释放更新锁。

我能想到使用该if exists方法的唯一原因是UPDATE/DELETE表中是否存在您想要避免被INSTEAD OF触发的触发器,特别是如果您有可以在实际尝试任何更新或删除之前采取某些操作的触发器。

通常最好编写 DML,以便只影响需要更改的行。