Consejos sobre el diseño de bases de datos
Cuando se diseña una base de datos, se pueden cometer una serie de errores u olvidos que, posteriormente, nos pueden causar bastantes quebraderos de cabeza, o se puede dejar de utilizar algún recurso útil simplemente por desconocimiento. En este artículo os daré una serie de consejos que os pueden ayudar a diseñar y gestionar mejor vuestros datos y las aplicaciones que los manejan, sobre todo si sois principiantes.
Utilizar claves subrogadas
Todas las tablas de la base de datos tienen normalmente una clave primaria para identificar de forma unívoca cada registro. Las claves subrogadas son un campo de tipo numérico, normalmente de tipo autoincremental (MySQL, SQL Server) o generado mediante una secuencia (Oracle), cuya única función es servir de clave primaria de la tabla.
La ventaja de utilizar este tipo de claves es que no dependen de las restricciones y cambios del modelo de datos. Un conjunto de campos que inicialmente debe tener valores únicos puede convertirse, por algún cambio en las especificaciones, en una clave no válida para la tabla. Además, los índices creados sobre un campo de tipo numérico son más rápidos de consultar y ocupan menos espacio que los creados sobre un conjunto de campos, y las consultas son más fáciles de escribir.
Crear un campo de fecha de creación del registro
Cuando un proceso de la base de datos puede crear registros en varias tablas, resulta de utilidad tener un campo en ellas que indique la fecha y hora de creación del registro. Esto nos puede ayudar a detectar cuellos de botella a la hora de optimizarlo.
También puede resultar útil un campo con la fecha de la última modificación, por ejemplo para automatizar la actualización de los datos entre un servidor de desarrollo y uno de producción.
Marcar el registro actual en una tabla con datos históricos
En algunas ocasiones, una tabla guarda registros sobre el estado de una entidad que nos puede interesar conservar para analizar su evolución en el tiempo, pero solamente uno de ellos representa el estado actual. En este tipo de tablas nos puede interesar utilizar un campo para marcar este registro, de manera que evitemos realizar subconsultas del tipo:
SELECT * FROM TABLA
JOIN (SELECT MAX(CLAVE), FK, DATOS FROM ESTADO GROUP BY FK, DATOS) SQ
ON TABLA.FK = SQ.FK
Y las sustituyamos por algo así:
SELECT * FROM TABLA JOIN ESTADO ON TABLA.FK = ESTADO.FK AND ESTADO.ACTUAL = 1
No duplicar información en varias tablas
Aunque a veces puede resultar tentador poner en una tabla información que ya está contenida en otra para simplificar las consultas, esto no debe hacerse nunca, ya que puede tener como consecuencia que se produzcan inconsistencias en los datos. Es preferible crear un índice sobre dicho campo o campos si se va a utilizar como filtro en las consultas o crear una vista que presente los datos de una forma unificada.
Aislar el acceso a los datos del resto de la aplicación
Al desarrollar una aplicación que debe acceder a una base de datos, resulta conveniente separar la parte que accede directamente a la base de datos del resto de la aplicación, mediante una librería de clases o un marco de trabajo como EntityFramework. Esto facilitará la tarea de adaptar la aplicación en el caso de que decidamos cambiar de servidor de base de datos o queramos hacer una aplicación que sea independiente del servidor utilizado, mediante un simple cambio de la librería de clases.
Definir siempre las restricciones de claves foráneas
Aunque en ocasiones puede resultar tedioso definir una constraint de clave externa cada vez que relacionamos una tabla con otras, se deben definir siempre que sea posible, ya que nos garantizan la integridad de los datos. Además, esto facilita el trabajo con las aplicaciones de administración y desarrollo de bases de datos, automatizando algunas tareas como la creación de diagramas y creación de relaciones entre los objetos que mapean las tablas.
Utilizar siempre consultas parametrizadas
Cuando escribimos un programa que utiliza una base de datos, en ocasiones se comete el error de construir una consulta concatenando los valores de los campos que queremos usar como filtro, por ejemplo con los datos introducidos por el usuario en un control TextBox. Esto no debe hacerse nunca por dos motivos principales: por un lado, si lanzamos una consulta construida de esta manera, cada vez será diferente para el motor de base de datos, con lo que tendrá que analizarla cada vez y no podrá almacenarla en la caché, con lo que el rendimiento de la aplicación será peor.
El otro motivo tiene que ver con la seguridad. Existe un tipo de ataque, conocido como SQL injection, mediante el cual un usuario malintencionado puede introducir como valor algo como:
(DELETE FROM TABLA)
Si concatenamos esto a una sentencia SQL, se convertirá en:
SELECT * FROM TABLA WHERE CAMPO = (DELETE FROM TABLA)
Con las consecuencias previsibles. Para evitar esto, se deben utilizar siempre consultas con parámetros, y pasar los valores introducidos por el usuario en dichos parámetros. Es más eficiente y más seguro.
Conocer y utilizar el catálogo del servidor
Los servidores de bases de datos tienen una serie de vistas, tablas y procedimientos almacenados que constituyen el catálogo, donde se almacena toda la información sobre los objetos de las diferentes bases de datos, nombres y campos de las tablas y vistas, sus tipos de datos, etc. Esta información resulta muy útil cuando se desarrollan herramientas o scripts de mantenimiento. SQL Server y MySQL tienen un catálogo muy similar, mientras que Oracle proporciona unas vistas totalmente diferentes.
Utilizar vistas o procedimientos almacenados para consultas complejas
Las consultas complejas que se ejecutan a menudo es mejor implementarlas mediante una vista o procedimiento almacenado. Esto evitará que tengas que modificar tu aplicación de acceso a los datos cada vez que haya que modificar la consulta. Piensa que cuanto más compleja sea una consulta, más probabilidades habrá de que haya que modificar algo en algún momento.
Implementa siempre que puedas acceso a los datos asíncrono
No hay nada más frustrante para un usuario de un programa que tener que esperar a que termine de ejecutarse una consulta que ha lanzado para poder continuar trabajando. Cuando las consultas pueden ser costosas en tiempo, siempre es mejor que el programa realice la consulta en segundo plano para que el usuario pueda realizar mientras tanto otras tareas con el programa.
Espero que estos consejos os ayuden a desarrollar mejores herramientas de acceso a datos, algo fundamental para poder considerarse un buen programador.