fc2ブログ
【メモ】レコードの一意挿入

前提として、一意列は一意制約を掛けている事とする。

public object InsertUnique( object 一意キー ) {
 // 重複チェック
 bool exists = exec( "SELECT 1 FROM [テーブル] WHERE [一意列]=一意キー" );
 if( exists )
   return 一意キー; // 既に在るので終わり
 
 try {
  // 無かったので挿入
  exec( "INSERT [テーブル] ([一意列]) VALUES (一意キー)"  );
 }
 catch( SqlException ex ) 
 {
  if( ex.Number == 1 ) { // 一意制約による例外なので、もう一度重複チェック
   bool exists = exec( "SELECT 1 FROM [テーブル] WHERE [一意列]=一意キー" );
   if( exists )
     return 一意キー;
  }
  throw;
 }
}

SQL Server の 2005 までには、ある列に対して一意にレコードを挿入したり更新したりといった操作がアトミックに提供されていない。
トランザクションで囲おうとも、まだ挿入されていないキーに対しる行ロックは取得できないので、粒度の荒いロック(主にテーブルロック)となりパフォーマンス上好ましくない。

なので、取り敢えず挿入前に一意キーを条件に重複チェックを行い、無ければ直後に挿入という策をとる。
もし重複チェックから挿入までの間に、他のスレッドやプロセスから今挿入しようとしている一意キーが挿入されてしまっていれば、一意制約違反が SQL Server から返されるので、もう一度重複チェックを行い、真偽を確かめる(再チェックはなくても良いかも知れない)。

はじめから挿入を行い、一意制約違反が起きたら終わりにしてしまっても良いかも知れないが、異常系処理を正常フローに含めるのもどうかと思う。
もっとも一番重視すべきはパフォーマンスなのだが、これは未検証・・・
パフォーマンスが必要な箇所は、個別の対応が必要かと。

スポンサーサイト



テーマ:データベース - ジャンル:コンピュータ

【2008/07/30 13:17】 | SQL Server | トラックバック(0) | コメント(0) | page top↑
| ホーム |