SQL Server - How, um einen Datensatz einfügen, und stellen Sie sicher, es ist einzigartig

StackOverflow https://stackoverflow.com/questions/267804

  •  06-07-2019
  •  | 
  •  

Frage

Ich versuche herauszufinden, der beste Weg, um einen Datensatz einfügen, in einer einzigen Tabelle, sondern nur, wenn der Artikel nicht bereits vorhanden ist.Der SCHLÜSSEL in diesem Fall ist ein NVARCHAR(400) Feld.Für dieses Beispiel können so tun, es ist der name einer Wort im Oxford English Dictionary / legen Sie Ihre fav-Wörterbuch hier.Auch, ich vermute, ich werde machen müssen, das Wort Feld ein Primärschlüssel.(die Tabelle wird auch eine eindeutige Kennung PK auch).

So ..ich könnte diese Worte, die ich hinzufügen müssen auf den Tisch...

zB.

  • Cat
  • Hund
  • Foo
  • Bar
  • PewPew
  • etc...

So traditionell, würde ich versuchen, die folgenden (pseudo-code)

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

ie. Wenn das Wort nicht vorhanden ist, dann fügen Sie es.

Nun ..das problem was ich bin besorgt ist, dass wir immer VIEL erwischt ..so ist es möglich, dass das Wort eingefügt werden könnte, von einem anderen Prozess in zwischen das AUSWÄHLEN und EINFÜGEN ..das wäre dann werfen Sie einen constraint-Fehler?(dh.ein Race Condition).

Ich habe mir dann gedacht, dass ich vielleicht in der Lage sein, Folgendes zu tun ...

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

im Grunde, fügen Sie ein Wort, wenn es nicht vorhanden ist.

Bad syntax beiseite, ich bin mir nicht sicher, ob dies schlecht oder gut ist, weil, wie es sperrt die Tabelle (wenn es funktioniert) und ist nicht performant auf einem Tisch, dass es immer massive liest und viel schreibt.

So was tun Sie Sql gurus denken / tun?

Ich war in der Hoffnung, einen einfachen einfügen und 'catch', dass für etwaige Fehler geworfen.

War es hilfreich?

Lösung

Ihre Lösung:

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

...ist ungefähr so gut wie es bekommt.Man könnte es vereinfacht so:

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

...da EXISTIERT gar nicht wirklich brauchen, um wieder alle Datensätze der Abfrage-Optimierer nicht die Mühe der Suche auf die Felder, die Sie gefragt haben.

Wie Sie erwähnen, dies ist jedoch nicht besonders performant, da es gesperrt werde die ganze Tabelle während des Einsatzes.Außer, dass, wenn Sie hinzufügen einen eindeutigen index (es muss nicht der Primärschlüssel) zu Wort, dann es müssen nur sperren den entsprechenden Seiten.

Ihre beste option ist die Simulation der erwarteten Last und betrachten Sie die Leistung mit SQL Server Profiler.Wie bei jedem anderen Feld, vorzeitige Optimierung ist eine schlechte Sache.Definieren akzeptable performance-Metriken, und Messen Sie dann, bevor Sie etwas anderes tun.

Wenn das immer noch nicht geben Ihnen ausreichend Leistung, dann gibt es eine Reihe von Techniken aus dem data-warehousing-Bereich, die helfen könnten.

Andere Tipps

Ich glaube, ich habe eine bessere gefunden (oder zumindest schneller) Antwort auf diese. Erstellen Sie einen Index wie:

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]

Fügen Sie alle Spalten, die Einzigartigkeit definieren. Der wichtigste Teil ist IGNORE_DUP_KEY = ON. Das macht nicht einzigartig Einsätze in Warnungen. SSIS ignoriert diese Warnungen und Sie können nach wie vor FASTLOAD- verwenden.

Wenn Sie MS SQL Server verwenden, können Sie einen eindeutigen Index für Ihre Tabellenspalten erstellen, müssen eindeutig (dokumentiert hier ):

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

Geben Sie Clustered oder NonClustered, je nach Fall. Auch, wenn Sie wollen, dass es sortiert (zu ermöglichen, schneller suchen), ASC oder DESC für die Sortierreihenfolge angeben.

Siehe hier , wenn Sie mehr über Indizes Architektur lernen wollen.

Sie können sonst UNIQUE CONSTRAINTS wie dokumentiert verwenden hier :

ALTER TABLE Words
ADD CONSTRAINT UniqueWord
UNIQUE (Word); 

Ich hatte ähnliches Problem, und das ist, wie ich es gelöst

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
    ) 

, während eindeutige Einschränkung certaily eine Möglichkeit ist, dass Sie dies auch für Ihren Einsatz Logik verwenden, um zu gehen: http://www.sqlteam.com/ Artikel / application-Schlösser-or-mutexes-in-sQL-Server-2005

basicaly setzen Sie keine Sperren für die Tabelle unten so nicht sich Gedanken über die liest während existance Kontrollen werden in Ordnung durchgeführt wird.

Es ist ein Mutex in SQL-Code.

Ich kann nicht auf die Einzelheiten des MS SQL sprechen, aber ein Punkt eines Primärschlüssels in SQL ist die Eindeutigkeit zu gewährleisten. So per Definition in generic SQL Begriffen, ein Primärschlüssel ist ein oder mehr Felder, die auf eine Tabelle eindeutig ist. Zwar gibt es verschiedene Möglichkeiten gibt, dieses Verhalten zu erzwingen (ersetzen die alten Eintrag mit der neuen gegenüber den neuen ablehnen) Ich wäre überrascht, wenn MS SQL beide keinen Mechanismus für die Durchsetzung dieses Verhalten hatte und dass es nicht zu den neuen Eintrag ablehnen. So stellen Sie sicher, dass Sie den Primärschlüssel auf das Wort-Feld gesetzt und es sollte Arbeit.

Wieder obwohl, ich lehnen dies alles von meinem Wissen von MySQL Programmierung und meine Datenbanken Klasse, so entschuldige mich, wenn ich auf die Feinheiten der MS SQL bin aus.

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top