Está en la página 1de 2

Soluciones para actualizar un registro si existe, sino insertar en SQL Server.

Filed under: SQL Server, T-SQL


grimpi @ 2:06 am
Muchas veces cuando trabajamos con ABMs o algn proceso de escritura en la base de
datos, al actualizar los registros, debemos establecer si vamos a efectuar un I
NSERT o un UPDATE. O sea, tenemos que determinar si el registro existe o no, par
a saber que operacin se va a efectuar en la base de datos.
Generalmente se suele encapsular toda esta lgica dentro de un SP, algo que consid
ero una muy buena practica, ya que nos desentendemos del lado de la aplicacin, si
se va a efectuar una operacin de insercin o de modificacin.
Primera solucin:
Ahora bien, dentro del Store Procedure, lo solemos hacer para determinar la oper
acin, es el famoso IF EXISTS.
Ejemplo:
IF EXISTS(SELECT ID FROM TABLA WHERE ID = @ID)
INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID)
ELSE
UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID
No es un mal enfoque, es muy claro. Sin embargo esta solucin tiene dos inconvenie
ntes:
1) Estamos pagando el costo de ejecutar un Query. Por mas que la consulta este i
ndexada, tiene un costo.
2) No es 100% segura. En entornos muy demandantes, con alta concurrencia, puede
darse el caso de que justo luego de ejecutar el IF EXISTS, otro proceso inserte
en la tabla un registro con la misma PK y no tendramos forma de darnos cuenta, ge
nerando un error de duplicate key.
Por lo tanto, esta opcin que es la ms comn, tiene serios inconvenientes.
Segunda solucin:
Una segunda opcin podra ser esta:
UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID
IF @@ROWCOUNT = 0
INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID)
En caso, se eliminara el tener que ejecutar una query con el EXISTS. Aunque en ca
so de que no exista el registro, se ejecuta el UPDATE innecesariamente.
Si la mayora de las operaciones van a ser del tipo INSERT, en realidad no se gana
ra performance, pero por el contrario, si la mayora de las operaciones seria del t
ipo UPDATE, podra llegar a ser mas performante.
De todas maneras esta solucin sigue teniendo el problema de que otro proceso podra
insertar un registro con la misma PK en la tabla y no tendramos forma de darnos
cuenta.
Tercera solucin:
En el segundo caso ganamos un poco de performance (no siempre), pero seguimos co
n el mismo problema de concurrencia.
Pero ahora veamos este ejemplo de cdigo:
BEGIN TRY
INSERT INTO TABLA (Campo1,ID) VALUES (@Valor,@ID)
END TRY
BEGIN CATCH

UPDATE TABLA SET Campo1 = @Valor WHERE ID = @ID


END CATCH
A nivel perfomance, es similar a las otras soluciones, pero si tenemos muchas ms
operaciones de insercin que de actualizacin, vamos a ganar velocidad.
Sin embargo, en este caso no tendramos el inconveniente de concurrencia que suced
e en los 2 casos anteriores!!. Lo cual lo hace ideal para situaciones de alta de
manda.
Cuarta solucin (Solo en SQL Server 2008):
SQL Server 2008, incorpora el comando MERGE (que ya tenamos en Oracle y otros mot
ores), que sirve para resolver de una manera muy eficiente, exactamente este pro
blema.
MERGE TABLA
USING (SELECT @ID AS ID) AS SRC ON SRC.ID = TABLA.ID
WHEN MATCHED THEN
UPDATE SET Campo1 = @Valor
WHEN NOT MATCHED THEN
INSERT (Campo1,ID) VALUES (@Valor,@ID)
Con este mtodo, tambin solucionamos el problema de concurrencia, y adems evitar ten
er que ejecutar consultas innecesarias. Por lo cual, podramos decir que es la opt
ima solucin resolver este problema, aunque lamentablemente debemos esperar hasta
mitad de ao, cuando Microsoft libere SQL Server 2008.
Conclusin:
Vimos como un problema en apariencia tonto y trivial, puede causar serios proble
mas de performance y peor aun, crear errores de concurrencia y comportamientos n
o deseados.
Por las pruebas que hicimos en un entorno de TEST, la diferencia de performance
que hicimos no son demasiadas. Pero en situaciones de alta concurrencia, las 2 p
rimeras soluciones son definitivamente incorrectas.
Recomiendo ver estos links, que explican como funcionan los lockeos, en cada una
de las distintas soluciones:
http://weblogs.sqlteam.com/mladenp/archive/2007/07/30/60273.aspx
http://weblogs.sqlteam.com/mladenp/archive/2007/08/03/60277.aspx
Y estas soluciones alternativas al mismo problema, tal vez sean un poco ms comple
jas, pero en algunos escenarios pueden ser tiles:
http://www.samsaffron.com/blog/archive/2007/04/04/14.aspx
http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

También podría gustarte