Los Stored Proceedures son tus amigos

En todos los lugares en los que he trabajado, la figura del DBA es bastante habitual, y es normal, hace falta al menos una persona para la labor, que además tenga la experiencia y los nervios para trabajar con datos reales sin destrozar el negocio en pocos segundos. Los pobres tienen que convivir con usuarios, clientes y desarrolladores, y de vez en cuando, con la dirección. Todos pidiendo informes extraños y miles de cosas que además, tienen que implementar con algo tan doloroso como es SQL (para mi, al menos).
Gracias a herramientas como Hibernate, y muchas otras, los programadores podemos olvidarnos de SQL y concentrarnos en nuestro lenguaje. Pero no siempre una capa de persistencia es la solución.
Muchas veces, nos encontramos con que la información está en distintos lugares (queues, BB.DD., sistemas de ficheros) pero el caso más común, es conectarte a distintas BB.DD. para obtener ingentes cantidades de información o verificaciones sobre datos y es aquí donde no vamos a utilizar estas herramientas, ya que realmente no vamos a realizar ninguna tarea de persistencia, sólo vamos a utilizar la R de CRUD.
¿Hasta dónde debemos llegar con estas búsquedas? En mi opinión, cualquier búsqueda más complicada que un SELECT x FROM y WHERE a = b debe ser un procedimiento almacenado.
Los stored procedures o sp nos permiten obtener un nuevo nivel de abstracción entre el código y los datos. Son una caja negra con la que siempre debemos cumplir y la que siempre debe cumplir con sus especificaciones. Es decir, si al sp_test yo le doy dos enteros y espero que me devuelva una cadena, siempre debe ser así. Internamente, el sp puede cambiar, pero siempre que se ciña al contrato, el código (probablemente, desplegado en producción o distribuido a miles de empleados) no tiene por que cambiar.
Además, es mucho más fácil buscar y modificar un sp ya que estos están en un mismo sitio. Probablemente, los cree o modifique un DBA que conoce SQL en lugar de un programador con dudosa experiencia en SQL. Y el código queda mucho más legible y limpio, ya que no hace falta interpretar una query gigante.
Ejemplo gráfico:
Esta es una query perfecta para nuestro ejemplo: es bastante larga, tiene una finalidad bien definida y los parámetros son siempre los mismos:


private final static String QUERY_ENTRIES_NEEDING_HARVEST =
"SELECT entries.id, entries.permalink, age(now(), harvested_at) " +
"FROM watched_pages " +
"INNER JOIN entries ON watched_pages.entry_id = entries.id " +
"WHERE feed_id = 0 AND (harvested_at IS NULL OR " +
"(age(now(), harvested_at) > interval '24:00:00' AND has_microformats = 't'))";


Esto puede convertirse en la pesadilla de algún programador, ya que buscar fallos en código SQL desde otro lenguaje es realmente doloroso: no se tiene syntax highlighting, verificación de datos (¿la tabla existe o no?¿está bien la llamada a la tabla o era X.dbo.Y?). Si además, el próximo programador, no tiene ni idea de SQL, ya es un largo tiempo que tendrá que utilizar para aprender qué demonios es INNER JOIN con los consiguientes problemas que esto acarrea. Si el nombre de alguna tabla cambia, habrá que realizar un nuevo despliegue o distribución de la aplicación corregida.
La solución habría sido darle esta query o un "contrato" a tu DBA especificando tus necesidades, lo que puedes proveer y lo que deseas recibir. Una query así, para un programador, puede resultar bastante complicada de entender, pero para un DBA, con sus herramientas específicas y con sus amplios conocimientos, esto es como ver un "Hello World". Probablemente, el DBA nos devolverá un correo para decirnos que ya podemos utilizar el sp sp_entries_needing_harvest(). Y nuestro código será algo como esto:


//...
CallableStatement cstmt = cx.prepareCall("{ ? = call sp_query_entries_needing_harvest()}");
cstmt.registerOutParameter(1, Types.VARCHAR);
//...


De ésta manera, además de abstraer un poco más nuestro código de los datos, estamos delegando tareas y responsabilidades en quien debe ser: el DBA. Si algo falla en esa sp el marrón será del él/ella :)