2010-02-16 17 views
27

Ho una domanda riguardante le prestazioni di SQL Server.T-SQL Inserimento o aggiornamento

Supponiamo che io sono un tavolo persons con le seguenti colonne: id, name, surname.

Ora, voglio inserire una nuova riga in questa tabella. La regola è la seguente:

  1. Se id non è presente nella tabella, quindi inserire la riga.

  2. Se id è presente, quindi aggiornare.

ho due soluzioni qui:

Prime:

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) 

Second:

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) 

Che cosa è un approccio migliore? Sembra nella seconda scelta, per aggiornare una riga, deve essere perquisito due volte, mentre nella prima opzione, solo una volta. Ci sono altre soluzioni al problema? Sto usando MS SQL 2000.

+1

non è sicuro, ma vorrei solo fare un if ((COUNT (*))> 0) quindi aggiornare per la seconda opzione –

risposta

7

Entrambi funzionano bene, ma io di solito uso l'opzione 2 (pre-mssql 2008) dal momento che legge un po 'più chiaro. Non vorrei sottolineare le prestazioni qui ... Se diventa un problema, è possibile utilizzare NOLOCK nella clausola exists. Anche se prima di iniziare a utilizzare NOLOCK ovunque, assicurati di aver coperto tutte le tue basi (indici e materiale di architettura di grandi dimensioni). Se sai che aggiornerai ogni articolo più di una volta, potrebbe essere necessario considerare l'opzione 1.

L'opzione 3 non deve utilizzare aggiornamenti distruttivi. Richiede più lavoro, ma in pratica si inserisce una nuova riga ogni volta che i dati cambiano (non si aggiornano o eliminano mai dalla tabella) e si dispone di una vista che seleziona tutte le righe più recenti. È utile se vuoi che la tabella contenga una cronologia di tutti i suoi stati precedenti, ma può anche essere eccessivo.

11

L'opzione 1 sembra buona. Tuttavia, se si utilizza SQL Server 2008, è possibile utilizzare anche MERGE, che potrebbe funzionare correttamente per tali attività UPSERT.

Si noti che è possibile utilizzare una transazione esplicita e l'opzione XACT_ABORT per tali attività, in modo che la coerenza della transazione rimanga nel caso di un problema o di una modifica simultanea.

2

Con l'obiettivo di essere un po 'più ASCIUTTO, evito di scrivere due volte la lista dei valori.

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 

Colonne name e surname devono essere annullabile.

La transazione significa che nessun altro utente vedrà mai il record "vuoto".

Edit: pulizia

+1

elegante, ma si dovrà inserire anche il valore di ogni non nullo campo nella tabella. –

+0

Vero. Tendo ad evitare qualsiasi uso funzionale di 'not null'. L'applicazione deve essere abbastanza carina da caricare null per campi importanti – Patrick

+0

La mia soluzione finale alla fine era di fare la logica in PHP, per 'put' - tentare un inserto completo, e se fallisce con' $ sqlErrors [0] [1] == 2627', faccio un aggiornamento completo – Patrick

0

Si potrebbe utilizzare @@ RowCount per vedere se l'aggiornamento ha fatto nulla. Qualcosa di simile:

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