web-dev-qa-db-ja.com

更新または削除の前に存在する場合?

  1. 更新ステートメントを書く前に、それが存在するかどうかを確認する必要がありますか?

    誰かがこれをするように言った

    1. そのため、すでに存在する値のトランザクションログへの無駄な書き込みを回避できます。

    2. また、共有ロックのみを取得し、他の読み取りと排他ロックを許可します。
      彼らは、異なる値に対してこのようなトランザクションが複数回実行されることを想像してください。共有ロックではなく、常に排他ロックを取得することになります。

    3. 同僚が言及し、 ロック互換性チャート を見て、検索時に2つの更新ロックはあり得ませんが、2つの共有ロックはあり得ます。したがって、更新する値がない場合に「更新する行を検索する」ときに、偽の更新ロックが実際の更新をブロックする可能性があります。誰かがこの主張を無効にすることはできますか?

      if not exists 
      (
          select FavoriteColor 
          from dbo.Person 
          where Name = 'Bob' 
          and FavoriteColor = 'Green'
      )
      update dbo.Person
      set FavoriteColor = 'Green'
      where Name = 'Bob'
      
  2. 今すぐ削除する以外は同じ質問ですが、存在するかどうかを確認する必要がありますか?

    if exists 
    (
        select FavoriteColor 
        from dbo.Person 
        where Name = 'Bob' 
        and FavoriteColor = 'Green'
    )
    delete dbo.Person
    where Name = 'Bob' and FavoriteColor = 'Green'
    

SQL Server 2016を使用しています。

1
user129291

一般に、このパターンはより効率的であり、デッドロックやその他の同時実行性の問題を引き起こす可能性ははるかに低くなります。

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

DELETE dbo.Person
  WHERE Name = 'Bob' 
  AND FavoriteColor = 'Green';
_

...単に行を確認する必要があるのは単純だからです。 UPDATEは次のように書くこともできます。

_UPDATE dbo.Person
  SET FavoriteColor = 'Green'
  WHERE Name = 'Bob'
  AND (FavoriteColor IS NULL OR FavoriteColor <> 'Green');
_

...場合によっては、よりインデックスに適したものになります。

書き込み操作の排他ロックは、変更する行が実際に更新される直前まで取得されません。 SQL Serverは更新する行に対してsearchingですが、同時読み取りと競合しない更新ロックを使用します。チェック対象の行が更新に適格でないとSQL Serverが判断した場合、更新ロックはすぐに解放されます。

_if exists_メソッドの使用を検討できる唯一の理由は、テーブルに_UPDATE/DELETE_トリガーが実行されないようにする場合、特に_INSTEAD OF_トリガーがいくつかあり、更新または削除が実際に試行される前のアクション。

通常、変更が必要な行のみが影響を受けるようにDMLを記述するのが最善です。

6
Aaron Bertrand