Pros y contras de verificar si existe un valor para una columna única o dejar que db genere un error único al insertar
8
Mientras escribía una consulta el otro día, se me ocurrió una idea que se me quedó grabada.
¿Qué es preferible, primero verificar si existe un valor para una columna única y luego insertar o insertar y dejar que db genere un error de restricción único? ¿Importará?
Editar: como se sugiere a continuación en respuesta que este problema depende de la base de datos, estoy agregando la etiqueta postgresql.
No creo que su pregunta sea realmente independiente de la base de datos. La respuesta correcta podría depender de los detalles de implementación, que pueden variar de un proveedor a otro y cambiar con la próxima versión. Probaría bajo concurrencia antes de elegir cualquier enfoque en cualquier RDBMS.
En este momento, en SQL Server 2008 R2, estoy usando lo siguiente:
Baja concurrencia y baja cantidad de modificaciones. Para guardar una sola fila, serializo usando sp_getapplock y uso MERGE. Pruebo de estrés bajo alta concurrencia para verificar que funcione.
Mayor concurrencia y / o volumen. Para evitar la concurrencia y aumentar el rendimiento, no guardo una fila a la vez. Acumulo cambios en mi servidor de aplicaciones y uso TVP para guardar lotes. Aún así, para evitar problemas relacionados con la concurrencia, serializo usando sp_getapplock antes de MERGE. Una vez más, hago una prueba de estrés bajo alta concurrencia para verificar que funcione.
Como resultado, tenemos un buen rendimiento y cero problemas relacionados con la concurrencia en la producción: sin puntos muertos, sin PK / violaciones de restricciones únicas, etc.
¿quiere decir que si los problemas de concurrencia se manejan bien, entonces verificar es una buena idea?
codecool
1
Sí, por lo general, evitar errores funciona mejor que lanzar y capturar excepciones, pero debe compararlo en su plataforma.
AK
7
Deje que el DB genere un error.
La prueba primero no es segura para la concurrencia porque eventualmente obtendrá una colisión porque 2 hilos pueden pasar "NO EXISTENTE" y ambos intentarán escribir. Esto se aplica tanto a las estrategias de bloqueo "LEER COMPROMETIDO" como MVCC / Instantánea.
Puede usar sugerencias de bloqueo para forzar el aislamiento, pero reduce el rendimiento.
Creo que es útil realizar la verificación (y fallar con gracia) pero seguir el adagio de "confiar pero verificar" para detectar la falla. ¿La razón? El manejo de errores es costoso. Estoy trabajando en algunas pruebas hoy, en realidad, eso debería revelar si este comentario tiene sentido. Si este comentario desaparece, ya sabes el resultado. :-)
Aaron Bertrand
También en 2008 hay algunas MERGEque pueden haber resuelto las observaciones de Paul, pero no lo he probado a altas tasas de transmisión. Principalmente porque todavía tengo que entrenar mi cerebro para entender esa sintaxis.
Aaron Bertrand
1
Mea culpa. He hecho algunas observaciones en mis pruebas de hoy. Tenga en cuenta que estas son pruebas muy aisladas sin concurrencia. Para inserciones rectas, verificar primero y evitar el error es aproximadamente 10 veces más rápido que dejar que ocurra el error. Pero en otros casos donde va a hacer un manejo de errores más complejo (TRY / CATCH o IF @@ ERROR <> 0, con ROLLBACK o THROW, etc.) es aproximadamente el doble de lento si verifica primero. Nuevamente enfatizaré que estas son solo mis observaciones iniciales y hay muchos factores que pueden influir en el impacto que puede tener. Puede pasar algún tiempo antes de que pueda bloguear al respecto a fondo.
Deje que el DB genere un error.
La prueba primero no es segura para la concurrencia porque eventualmente obtendrá una colisión porque 2 hilos pueden pasar "NO EXISTENTE" y ambos intentarán escribir. Esto se aplica tanto a las estrategias de bloqueo "LEER COMPROMETIDO" como MVCC / Instantánea.
Puede usar sugerencias de bloqueo para forzar el aislamiento, pero reduce el rendimiento.
Yo llamo a esto el patrón JFDI (enlace SO). Para "actualizar si existe", vea esto aquí: Necesita ayuda Solución de problemas de Sql Server 2005 Deadlock Scenario . Estos son SQL Server. MySQL tiene INSERT IGNORE que maneja esto con gracia. No estoy seguro del resto
fuente
MERGE
que pueden haber resuelto las observaciones de Paul, pero no lo he probado a altas tasas de transmisión. Principalmente porque todavía tengo que entrenar mi cerebro para entender esa sintaxis.