2010-02-16 10 views
27

Ich habe eine Frage bezüglich der Leistung von SQL Server.T-SQL Einfügen oder Aktualisieren

Angenommen, ich habe eine Tabelle persons mit den folgenden Spalten: id, name, surname.

Jetzt möchte ich eine neue Zeile in diese Tabelle einfügen. Die Regel ist folgende:

  1. Wenn id nicht in der Tabelle vorhanden ist, dann die Zeile einzufügen.

  2. Wenn id vorhanden ist, aktualisieren Sie.

Ich habe zwei Lösungen hier:

Erstens:

update persons 
    set [email protected]_id, [email protected]_name, [email protected]_surname 
where [email protected]_id 
if @@ROWCOUNT = 0 
    insert into persons(id, name, surname) 
    values (@p_id, @p_name, @p_surname) 

Zweitens:

if exists (select id from persons where id = @p_id) 
    update persons 
    set [email protected]_id, [email protected]_name, [email protected]_surname 
    where [email protected]_id 
else 
    insert into persons(id, name, surname) 
    values (@p_id, @p_name, @p_surname) 

Was ist ein besserer Ansatz? Es scheint, dass in der zweiten Wahl, um eine Zeile zu aktualisieren, muss zweimal gesucht werden, während in der ersten Option - nur einmal. Gibt es andere Lösungen für das Problem? Ich verwende MS SQL 2000.

+1

nicht sicher, aber ich würde nur tun, wenn ((COUNT (*))> 0), dann aktualisieren, für die zweite Option –

Antwort

7

Beide arbeiten gut, aber ich verwenden Option in der Regel 2 (Pre-mssql 2008), da es ein wenig deutlicher liest. Ich würde auch nicht über die Leistung hier betonen ... Wenn es ein Problem wird, können Sie NOLOCK in der Klausel exists verwenden. Bevor Sie beginnen, NOLOCK überall zu verwenden, stellen Sie sicher, dass Sie alle Ihre Grundlagen (Indizes und Big Picture Architecture Zeug) abgedeckt haben. Wenn Sie wissen, dass Sie jeden Artikel mehr als einmal aktualisieren, ist es möglicherweise sinnvoll, Option 1 in Betracht zu ziehen.

Option 3 besteht darin, keine destruktiven Aktualisierungen zu verwenden. Es braucht mehr Arbeit, aber im Grunde fügen Sie jedes Mal eine neue Zeile ein, wenn sich die Daten ändern (niemals aktualisieren oder aus der Tabelle löschen), und haben eine Ansicht, die alle letzten Zeilen auswählt. Es ist nützlich, wenn Sie möchten, dass die Tabelle eine Historie aller vorherigen Zustände enthält, aber es kann auch Overkill sein.

11

Option 1 scheint gut. Wenn Sie jedoch SQL Server 2008 verwenden, können Sie auch MERGE verwenden, was sich für solche UPSERT-Aufgaben als nützlich erweisen kann.

Beachten Sie, dass Sie möglicherweise eine explizite Transaktion und die Option XACT_ABORT für solche Aufgaben verwenden möchten, sodass die Transaktionskonsistenz im Falle eines Problems oder einer gleichzeitigen Änderung erhalten bleibt.

2

Mit dem Ziel, etwas trockener zu sein, vermeide ich, die Werteliste zweimal zu schreiben.

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

update persons 
set [email protected]_name, [email protected]_surname 
where id = @p_id 

commit 

Spalten name und surname haben nullable sein.

Die Transaktion bedeutet, dass kein anderer Benutzer jemals den "leeren" Datensatz sehen wird.

Edit: Bereinigungs

+1

Elegant, aber Sie müssen auch den Wert legen Sie für jede nicht null Feld in der Tabelle. –

+0

Wahr. Ich tendiere dazu, jede funktionale Verwendung von 'not null' zu vermeiden. Die Anwendung muss hübsch sein, Nullen für wichtige Felder hochzuladen – Patrick

+0

Meine letzte Lösung war am Ende, die Logik in PHP zu tun, für 'put' - versuchen Sie eine vollständige Einfügung, und wenn es mit' $ sqlErrors [0] scheitert [1] == 2627', ich mache eine vollständige Aktualisierung – Patrick

0

Sie könnten nur RowCount verwenden @@, um zu sehen, ob das Update etwas tat. Etwas wie:

UPDATE MyTable 
     SET SomeData = 'Some Data' WHERE ID = 1 
    IF @@ROWCOUNT = 0 
     BEGIN 
     INSERT MyTable 
     SELECT 1, 'Some Data'  
     END