SQL Server - How, um einen Datensatz einfügen, und stellen Sie sicher, es ist einzigartig
-
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.
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