40

SQL Server のパフォーマンスについて質問があります。

persons次の列を持つテーブルがあるとします: idnamesurname

ここで、このテーブルに新しい行を挿入したいと思います。ルールは次のとおりです。

  1. がテーブルに存在しない場合idは、行を挿入します。

  2. 存在する場合idは、更新します。

ここには2つの解決策があります:

初め:

update persons
  set id=@p_id, name=@p_name, surname=@p_surname
where id=@p_id
if @@ROWCOUNT = 0 
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)

2番:

if exists (select id from persons where id = @p_id)
  update persons
    set id=@p_id, name=@p_name, surname=@p_surname
  where id=@p_id
else
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)

より良いアプローチは何ですか?2 番目の選択肢では、行を更新するには 2 回検索する必要があるようですが、最初の選択肢では 1 回だけです。問題に対する他の解決策はありますか?MS SQL 2000 を使用しています。

4

5 に答える 5

13

オプション 1 は良さそうです。ただし、SQL Server 2008 を使用している場合は、 MERGEを使用することもできます。これは、このような UPSERT タスクに適している場合があります。

このようなタスクには明示的なトランザクションとXACT_ABORTオプションを使用することをお勧めします。これにより、問題や同時変更が発生した場合でもトランザクションの一貫性が保たれます。

于 2010-02-16T20:25:00.397 に答える
12

どちらも問題なく動作しますが、通常はオプション 2 (mssql 2008 より前) を使用します。ここでもパフォーマンスについて強調しません...それが問題になる場合NOLOCKは、exists句で使用できます。ただし、どこでも NOLOCK を使い始める前に、すべてのベース (インデックスとアーキテクチャの全体像) をカバーしていることを確認してください。すべてのアイテムを複数回更新することがわかっている場合は、オプション 1 を検討することをお勧めします。

オプション 3 は、破壊的な更新を使用しないことです。より多くの作業が必要ですが、基本的に、データが変更されるたびに新しい行を挿入し (テーブルから更新または削除することはありません)、最新のすべての行を選択するビューを作成します。テーブルに以前のすべての状態の履歴を含めたい場合に便利ですが、やり過ぎになることもあります。

于 2010-02-17T00:52:50.033 に答える
5

私はオプション 1 を使用する傾向があります。テーブルにレコードがある場合は、1 つの検索を保存します。そうでない場合は、何も失うことはありません。さらに、2 番目のオプションでは、ロックの非互換性に関連する面白いロックおよびデッドロックの問題が発生する可能性があります。私のブログにはいくつかの詳細情報があります:

http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx

于 2010-02-16T23:58:14.967 に答える
3

もう少し DRY にすることを目指して、値リストを 2 回書き出すことは避けています。

begin tran
insert into persons (id)
select @p_id from persons
 where not exists (select * from persons where id = @p_id)

update persons
set name=@p_name, surname=@p_surname
where id = @p_id

commit

namesurnamenull 可能である必要があります。

このトランザクションは、他のユーザーが「空白」のレコードを見ることがないことを意味します。

編集:クリーンアップ

于 2016-10-18T23:54:40.120 に答える