22

レコードを単一のテーブルに挿入する最良の方法を見つけようとしていますが、アイテムがまだ存在しない場合に限ります。この場合の KEY は NVARCHAR(400) フィールドです。この例では、オックスフォード英語辞書の単語の名前であると仮定して、お気に入りの辞書をここに挿入します。また、Word フィールドを主キーにする必要があると思います。(テーブルには一意の識別子 PK も含まれます)。

だから..テーブルに追加する必要があるこれらの単語を取得するかもしれません...

例えば。

  • ネコ
  • フー
  • バー
  • ピューピュー
  • 等...

伝統的に、私は次のことを試します(疑似コード)

SELECT WordID FROM Words WHERE Word = @Word
IF WordID IS NULL OR WordID <= 0
    INSERT INTO Words VALUES (@Word)

すなわち。単語が存在しない場合は、挿入します。

今..私が心配している問題は、私たちがたくさんのヒットを取得していることです..そのため、SELECTとINSERTの間に別のプロセスから単語が挿入される可能性があります..その後、制約エラーがスローされます? (つまり、競合状態)。

次に、次のことができるかもしれないと考えました...

INSERT INTO Words (Word)
SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

基本的に、単語が存在しない場合は単語を挿入します。

悪い構文はさておき、これがテーブルをロックダウンする方法(ロックダウンする場合)と、大量の読み取りと大量の書き込みを行うテーブルでのパフォーマンスが低いため、これが悪いか良いかはわかりません。

では、Sqlの専門家は何を考えていますか/何をしますか?

スローされたエラーに対して、単純な挿入と「キャッチ」を行うことを望んでいました。

4

7 に答える 7

31

あなたの解決策:

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

…という程度でいいです。これを次のように単純化できます。

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word)

... EXISTS は実際にはレコードを返す必要がないため、クエリオプティマイザーは、要求されたフィールドを調べる必要がありません。

ただし、言及したように、これは INSERT 中にテーブル全体をロックするため、特にパフォーマンスが高いわけではありません。ただし、一意のインデックス (主キーである必要はありません) を Word に追加する場合は、関連するページをロックするだけで済みます。

最適なオプションは、予想される負荷をシミュレートし、SQL Server プロファイラーでパフォーマンスを確認することです。他の分野と同様に、時期尚早の最適化は悪いことです。許容できるパフォーマンス メトリックを定義し、他のことを行う前に測定します。

それでも十分なパフォーマンスが得られない場合は、データ ウェアハウス分野のさまざまなテクニックが役に立ちます。

于 2008-11-06T07:31:11.670 に答える
6

私はこれに対するより良い(または少なくともより速い)答えを見つけたと思います。次のようなインデックスを作成します。

CREATE UNIQUE NONCLUSTERED INDEX [IndexTableUniqueRows] ON [dbo].[table] 
(
    [Col1] ASC,
    [Col2] ASC,

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

一意性を定義するすべての列を含めます。重要な部分はIGNORE_DUP_KEY=ONです。これにより、一意でない挿入が警告に変わります。SSISはこれらの警告を無視し、引き続きfastloadを使用できます。

于 2011-10-20T16:05:52.010 に答える
3

私は同様の問題を抱えていましたが、これが私がそれを解決した方法です

insert into Words
( selectWord , Fixword)
SELECT word,'theFixword'
FROM   OldWordsTable
WHERE 
(
    (word LIKE 'junk%') OR
     (word LIKE 'orSomthing') 

)
and word not in 
    (
        SELECT selectWord FROM words WHERE selectWord = word
    ) 
于 2009-05-27T11:11:18.077 に答える
3

MS SQL Server を使用している場合は、一意である必要があるテーブルの列に一意のインデックスを作成できます (ドキュメントはこちら)。

CREATE UNIQUE [ CLUSTERED | NONCLUSTERED ] INDEX <index_name>
    ON Words ( word [ ASC | DESC ])

場合に応じてClusteredまたはを指定します。NonClusteredまた、並べ替えたい場合 (シークを高速化するため)は、並べ替え順序にASCorを指定します。DESC

インデックス アーキテクチャの詳細については、こちらを参照してください。

それ以外の場合は、ここUNIQUE CONSTRAINTSに記載されているように使用できます。

ALTER TABLE Words
ADD CONSTRAINT UniqueWord
UNIQUE (Word); 
于 2008-11-06T07:33:19.993 に答える
1

一意の制約は確かに 1 つの方法ですが、これを挿入ロジックに使用することもできます: http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

基本的に、以下のテーブルにロックを設定しないため、存在チェックが正常に実行される間、読み取りについて心配する必要はありません。

これは、SQL コードのミューテックスです。

于 2008-11-06T10:46:48.200 に答える
0

MS SQL の詳細について話すことはできませんが、SQL の主キーの 1 つのポイントは、一意性を確保することです。したがって、一般的な SQL 用語の定義では、主キーはテーブルに固有の 1 つまたは複数のフィールドです。この動作を強制するにはさまざまな方法がありますが (古いエントリを新しいエントリに置き換えるか、新しいエントリを拒否するか)、MS SQL の両方にこの動作を強制するメカニズムがなく、そうでなかったとしたら驚くでしょう。新しいエントリを拒否します。主キーを Word フィールドに設定していることを確認してください

繰り返しになりますが、これはすべて MySQL プログラミングとデータベース クラスから得た私の知識によるものであることは断言します。そのため、MS SQL の複雑さに疎い場合は申し訳ありません。

于 2008-11-06T08:29:08.337 に答える
-3
declare @Error int

begin transaction
  INSERT INTO Words (Word) values(@word)
  set @Error = @@ERROR
  if @Error <> 0 --if error is raised
  begin
      goto LogError
  end
commit transaction
goto ProcEnd

LogError:
rollback transaction
于 2008-11-06T11:02:04.380 に答える