2010-02-16 17 views
27

Tengo una pregunta sobre el rendimiento de SQL Server.T-SQL Insertar o actualizar

Supongamos que tengo una tabla persons con las siguientes columnas: id, name, surname.

Ahora, quiero insertar una nueva fila en esta tabla. La regla es la siguiente:

  1. Si id no está presente en la tabla, a continuación, insertar la fila.

  2. Si id está presente, entonces actualícela.

tengo dos soluciones aquí:

Primero:

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) 

Segundo:

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) 

¿Cuál es el mejor enfoque? Parece que en la segunda opción, para actualizar una fila, debe buscarse dos veces, mientras que en la primera opción, solo una vez. ¿Hay alguna otra solución al problema? Estoy usando MS SQL 2000.

+1

no estoy seguro, pero me gustaría hacer un if ((COUNT (*))> 0) y luego actualizar por la segunda opción –

Respuesta

7

Ambos funcionan bien, pero por lo general utiliza la opción 2 (pre-mssql 2008), ya que lee un poco más claramente. No me preocuparé por el rendimiento aquí tampoco ... Si se convierte en un problema, puede usar NOLOCK en la cláusula exists. Aunque antes de comenzar a usar NOLOCK en todas partes, asegúrese de haber cubierto todas sus bases (índices y elementos de la arquitectura general). Si sabe que va a actualizar cada elemento más de una vez, puede ser útil considerar la opción 1.

La opción 3 es no utilizar actualizaciones destructivas. Se necesita más trabajo, pero básicamente se inserta una nueva fila cada vez que los datos cambian (nunca se actualiza ni se elimina de la tabla) y se obtiene una vista que selecciona todas las filas más recientes. Es útil si desea que la tabla contenga un historial de todos sus estados anteriores, pero también puede ser exagerado.

11

La opción 1 parece buena. Sin embargo, si está en SQL Server 2008, también puede usar MERGE, que puede funcionar bien para dichas tareas UPSERT.

Tenga en cuenta que es posible que desee utilizar una transacción explícita y la opción XACT_ABORT para tales tareas, de modo que la coherencia de la transacción permanezca en el caso de un problema o cambio concurrente.

2

Con el objetivo de ser un poco más SECO, evito escribir la lista de valores dos veces.

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 

Columnas name y surname tienen que ser anulable.

La transacción significa que ningún otro usuario verá el registro "en blanco".

Editar: limpieza

+1

elegante pero usted tendrá que insertar también el valor de cada uno no nula campo en la mesa. –

+0

Es cierto. Tiendo a evitar cualquier uso funcional de 'not null'. La aplicación necesita estar bastante cargada para cargar nulos para campos importantes. – Patrick

+0

Mi solución final al final fue hacer la lógica en PHP, para 'put' - intentar una inserción completa, y si falla con' $ sqlErrors [0] [1] == 2627', hago una actualización completa – Patrick

0

Se podía utilizar @@ RowCount para ver si la actualización hizo nada. Algo así como:

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