El debate del infame SQL en línea vs. Los procedimientos almacenados
A lo largo de los años, ha existido un poco de debate entre usar SQL en línea o procedimientos almacenados. Este debate ha sido pobremente soportado, debido a que cuando la gente escucha SQL en línea, piensan en código mal escrito, algo como esto:
string sql = @"SELECT UserId FROM Users
WHERE UserName = '" + userName + "'
AND Password = '" + password + "'";
using (SqlCommand command = new SqlCommand(sql))
{
return 0; //todo
}
Por supuesto que formulado de esta manera, el SQL en línea realmente apesta. Sin embargo, si te detienes y lo piensas y realmente comparas manzanas con manzanas, la verdad es que ninguna de las 2 es particularmente mejor que la otra, Examinemos algunos puntos de interés.
Los procedimientos almacenados son más seguros
El SQL en línea debe ser escrito usando consultas parametrizadas de la misma forma en que lo haces con los procedimientos almacenados. Por ejemplo, la forma correcta de escribir el código de arriba para eliminar un posible ataque de inyección de SQL es:
string sql = @"SELECT UserId FROM Users
WHERE UserName = @UserName AND Password = @Password";
using (SqlCommand command = new SqlCommand(sql))
{
command.Parameters.Add("@UserName", SqlDbType.VarChar).Value = userName;
command.Parameters.Add("@Password ", SqlDbType.VarChar).Value = password;
return 0; //todo
}
De ahí en adelante, no hay mucha diferencia - se pueden usar vistas o configurar roles / usuarios de la base base datos con los permisos apropiados.
Los procedimientos almacenados proveen abstracción al esquema subyacente
Sin importar si estas usando SQL en línea o procedimientos almacenados, la pequeña porción de abstracción que puedes poner en una sentencia de SELECT es la misma. Si algún cambio substancial es realizado, tus procedimientos almacenados dejarán de funcionar y lo más probable es que tendrás que cambiar el código que los invoca para resolver este problema. Esencialmente, es el mismo código, solamente que reside en un lugar diferente, por lo tanto no puede proveer un grado más alto de abstracción. Las definiciones de conversión por otro lado, generalmente proveen una mejor abstracción ya que son configurables e implementan su propio lenguaje de consulta.
Si hago un cambio, no tengo que recompilar el código
En algún lugar, de alguna forma, la gente se metió en la cabeza que las compilaciones de código deben evitarse a toda costa (tal vez esto venga de los días cuando los proyectos podrían tardar días en compilar). Si cambias un procedimiento almacenado, aun tendrás que ejecutar nuevamente tus pruebas unitarias y de integración y liberar el cambio a producción. Realmente me espanta el que los desarrolladores consideren que un cambio a un procedimiento almacenado o a un XML es algo trivial comparado con un cambio similar al código.
Los procedimientos almacenados reducen el tráfico en la red
¿A quién le importa? En la mayoría de los casos tu base de datos esta soportada por una conexión GigE con tus servidores y tu no pagas ese ancho de banda. Estás hablando de fracciones de nanosegundos. Más relevante aún, una definición de conversión bien configurada puede ahorrarte viajes de ida y vuelta gracias a la identificación de las implementaciones de los mapas, el cache y la carga diferida.
Como he dicho antes, creo que es generalmente mejor errar en el lado de la simplicidad, siempre que sea posible. Escribir un montón de tontos procedimientos almacenados para realizar cada operación de base de datos que creas que vas a necesitar, definitivamente no es a lo que yo considero simple. Ciertamente no intento descartar el uso de los procedimientos almacenados, ¿pero comenzar con procedimientos? Parece un caso bastante extremo de optimización prematuro para mí. -Jeff Atwood.
Los procedimientos almacenados son más rápidos
Esta es la excusa más frecuentemente utilizada, Escribe una sentencia común y razonable de SQL en línea y después escribe lo mismo con un procedimiento almacenado y cronometra el tiempo de ejecución. Adelante hazlo. En la mayoría de los casos no habrá diferencia o esta será muy poca. En algunos casos los procedimientos almacenados serán más lentos ya que el plan de ejecución no será eficiente con algunos parámetros. Jeff Atwood catalogó el uso de procedimientos almacenados en busca de una mayor velocidad de ejecución como un caso extremo de optimización prematura. Tiene razón. El enfoque adecuado es tomar la estrategia más simple (permite que una herramienta genere el SQL por ti), y optimiza consultas especificas en caso de que identifiques cuellos de botella.
Me tomo un tiempo, pero después de un par de años, me di cuenta que el debate entre el SQL en línea y los procedimientos almacenados era tan trivial como el que se tiene con C# y VB.NET. Si tan solo se trataba de elegir uno u otro, entonces selecciona el que prefieras y continua con tu próximo reto. Si no hay nada más que decir sobre el tema, yo escogería procedimientos almacenados. Sin embargo, cuando añades una definición de conversión Objeto/Estructura relacional a la mezcla, de forma repentina obtendrás ventajas significativas. Dejas de participar en discusiones bizantinas para simplemente decir “quiero eso”.
Específicamente, hay tres grandes beneficios con las definiciones de conversión entre estructuras relacionales y objetos:
1.- Terminarás escribiendo mucho menos código – lo que obviamente resulta en un sistema más mantenible,
2.- Obtendrás un nivel real de abstracción del origen de datos subyacente – por una parte porque estarás consultando la definición de conversión para obtener los datos directamente (y esta a su vez convertirá eso en el SQL apropiado), por otra parte porque estarás proveyendo información de la definición de conversión entre los esquemas de tablas y los objetos de dominio,
3.- Tu código se vuelve más simple – si tu nivel de discrepancia entre los objetos y las estructuras relacionales es bajo, escribirás mucho menos código repetitivo. Si tu nivel de discrepancia entre los objetos y las estructuras es alto no tendrás que comprometer el diseño de la base de datos y el diseño del dominio – puedes construir ambos de una manera optimizada, y dejar que la definición de conversión maneje la discrepancia.
Al final, todo se traduce en la construcción de la solución más sencilla desde el inicio. La optimizaciones deberían dejarse para después de que el código ha sido perfilado y se han identificado los cuellos de botella reales. Como la mayoría de las cosas, podría no sonar tan sencillo por la complejidad en el aprendizaje de hacerlo por adelantado, pero esa es la realidad de nuestra profesión.