T-SQL Insertar o actualizar
Tengo una pregunta sobre el rendimiento de SQL Server.
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:
Si
id
no está presente en la tabla, inserte la fila.Si
id
está presente, entonces actualice.
Tengo dos soluciones aquí:
Primero:
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)
Segundo:
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)
¿Qué es un 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.
5 answers
Ambos funcionan bien, pero normalmente uso la opción 2 (pre-mssql 2008) ya que se lee un poco más claramente. Yo tampoco me estresaría por la actuación aquí...Si se convierte en un problema, puede usar NOLOCK
en la cláusula exists
. Sin embargo, antes de comenzar a usar NOLOCK en todas partes, asegúrese de haber cubierto todas sus bases (índices y cosas de arquitectura de imagen grande). Si sabe que actualizará cada artículo más de una vez, entonces podría pagar 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 actualizar o eliminar de la tabla) y tiene 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-17 00:52:50
La opción 1 parece buena. Sin embargo, si está en SQL Server 2008, también podría usar MERGE, que puede funcionar bien para tales tareas de UPSERT.
Tenga en cuenta que es posible que desee usar una transacción explícita y la opción XACT_ABORT para dichas tareas, de modo que la consistencia de la transacción permanezca en caso de un problema o cambio simultáneo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-16 20:25:00
Tiendo a utilizar la opción 1. Si hay un registro en una tabla, guarda una búsqueda. Si no lo hay, no pierdes nada. Además, en la segunda opción puede encontrarse con problemas de bloqueo y bloqueo divertidos relacionados con la incompatibilidad de bloqueos. Hay más información en mi blog:
Http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-16 23:58:14
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
Las columnas name
y surname
tienen que ser nullables.
La transacción significa que ningún otro usuario verá nunca el registro "en blanco".
Editar: limpieza
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-27 01:54:58
Solo puedes usar @@RowCount para ver si la actualización hizo algo. Algo como:
UPDATE MyTable
SET SomeData = 'Some Data' WHERE ID = 1
IF @@ROWCOUNT = 0
BEGIN
INSERT MyTable
SELECT 1, 'Some Data'
END
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-09 10:24:15