Pregunta

Tengo una pregunta respecto al rendimiento de SQL Server.

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

Ahora, quiero insertar una nueva fila de 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 actualizar.

Tengo dos soluciones aquí:

En primer lugar:

update persons
  set id=@p_id, name=@p_name, surname=@p_surname
where id=@p_id
if @@ROWCOUNT = 0 
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)

En segundo lugar:

if exists (select id from persons where id = @p_id)
  update persons
    set id=@p_id, name=@p_name, surname=@p_surname
  where id=@p_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, tiene que ser buscado dos veces, mientras que en la primera opción - sólo una vez. ¿Hay otras soluciones para el problema? Estoy usando MS SQL 2000.

¿Fue útil?

Solución

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 hincapié sobre el rendimiento aquí tampoco ... Si llega a ser un problema, puede utilizar NOLOCK en la cláusula exists. Aunque antes de empezar a usar NOLOCK en todas partes, asegúrese de que ha cubierto todas sus bases (índices y panorama arquitectura cosas). Si sabe que va a actualizar cada artículo más de una vez, entonces podría pagar la opción 1 para tener en cuenta.

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 cambian los datos (nunca actualizar o borrar de la tabla) y tienen una vista que selecciona todas las filas más recientes. Es útil si se desea que la tabla contiene un historial de todos sus estados anteriores, pero también puede ser excesiva.

Otros consejos

La opción 1 parece buena. Sin embargo, si estás en SQL Server 2008, se puede también utilizar MERGE , que puede llevar a cabo bien para este tipo de tareas upsert.

Tenga en cuenta que es posible que desee utilizar una transacción explícita y la XACT_ABORT opción para estas tareas, de manera que la consistencia transacción permanece en el caso de un problema o cambio concurrente.

tiendo opción de usar 1. Si hay registro de una tabla, se ahorra una sola búsqueda. Si no la hay, no perder nada. Por otra parte, en la segunda opción es posible que encuentre bloqueo y los interbloqueos cuestiones gracioso relacionados con cerraduras incompatibilidad. Hay un poco de más información en mi blog:

http: // sqlblogcasts .com / blogs / piotr_rodak / archivo / 2010/01/04 / UPDLOCK-holdlock-y-deadlocks.aspx

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 name=@p_name, surname=@p_surname
where id = @p_id

commit

Columnas name y surname tienen que ser anulable.

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

Editar: limpieza

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top