Las formas de guardar relaciones jerárquicas en bases de datos relacionales
Escrito por
el .
planeta-codigo
programacion
Enlace permanente
Comentarios
Para implementar relaciones jerárquicas en base de datos relacionales hay varias soluciones conocidas. En este artículo comento las más conocidas con sus desventajas y cual elegir en función de si la base de datos soporta consultas recursivas o en caso de que no las soporte.
Las bases de datos relacionales guardan los datos en tablas, filas y columnas. Los datos de unas tablas se relacionan con los de otras a través de las claves primarias y claves foráneas. Este modelo relacional permite guardar datos y es suficiente para muchos casos, habitualmente utilizando la tercera forma normal de las 6+2 formas normales de las bases de datos relacionales.
Sin embargo, el modelo relacional en principio no se ajusta a guardar relaciones jerárquicas, hay varias soluciones para implementar este tipo de relaciones en los datos en una base de datos relacional. Algunas soluciones aunque válidas en la teoría tiene importantes limitaciones en su uso práctico. Algunas solución depende de que la base de datos ofrezcan el soporte para implementarla en caso contrario hay que elegir otra opción.
En el libro SQL Antipatterns se trata con detalle las diferentes las formas de guardar relaciones jerárquicas en bases de datos relacionales entre otros diversos aspectos y buenas prácticas.
Contenido del artículo
Ejemplo de relación jerárquica
Las relaciones jerárquicas establecen unas normas en las relaciones de los elementos, los elementos se organizan en niveles en el que los elementos se relacionan como nivel por encima, por debajo o en el mismo nivel que otro. El número de niveles que tiene una estructura jerárquica es indefinido pudiendo tener cualquier profundidad.
Esta es una estructura pequeña jerárquica de productos con dos niveles de profundidad.
|
|
Formas de guardar relaciones jerárquicas
Adjacency List
La solución de listas adyacentes o adjacency list se basa en añadir un campo adicional a la tabla en el que cada fila guarda el identificador del elemento por encima en la estructura jerárquica.
Esta solución utiliza un modelo de datos sencillo, es fácil de añadir nuevos elementos a la estructura jerárquica además de mantener la integridad referencial.
|
|
|
|
Sus desventajas son que las consultas para obtener los ascendientes o descendientes de un elemento son complicadas e ineficientes además de no soportar cualesquiera niveles de profundidad.
Las consultas para obtener los ascendientes y los descendientes son las siguientes.
|
|
|
|
|
|
|
|
Para este caso y con consultas recursivas el ejemplo se puede probar con Docker y la base de datos PostgreSQL.
|
|
|
|
Consultas recursivas
Las otras implementaciones están originadas a la limitación del modelo relacional y del lenguaje SQL. En las últimas versiones de las bases de datos el lenguaje SQL soporta consultas recursivas o recursive queries con las que implementar la sencilla solución de adjacency list sin sus desventajas. MySQL soporta consultas recursivas desde la versión 8 y PostgreSQL ya era posible en la versión 9.
Las consultas para obtener los ascendientes y los descendientes son las siguientes.
|
|
|
|
|
|
|
|
Closure Table
Cuando la base de datos no soporta consultas recursivas una solución alternativa es la de closure table, esta se basa en guardar las relaciones entre los nodos en una tabla adicional, se guardan la relación de un nodo con todos sus descendientes o las de un nodo con todos sus ascendientes además de consigo mismo.
|
|
|
|
|
|
|
|
En este caso las consultas de búsqueda son eficientes, las de inserción son sencillas y hay integridad referencial. Esta solución permite a la misma fila formar parte de varias estructuras jerárquicas al mismo tiempo. Su desventaja es que requiere una tabla adicional.
Las consultas para obtener los ascendientes, los descendientes son las siguientes.
|
|
|
|
La de inserción.
|
|
Y para eliminar una rama del árbol.
|
|
Otras implementaciones
Estas otras soluciones son válidas para implementar estructuras jerárquicas en bases de datos relacionales. aunque en algunos aspectos con desventajas sobre las recomendadas de consultas recursivas si están soportadas por la base de datos o la solución de closure table.
Path Enumeration
La solución path enumeration se basa en añadir una columna que contiene en una cadena la colección de identificadores de sus ascendientes incluido el propio nodo.
|
|
|
|
Su desventaja es que al igual que la solución de nested set no ofrece integridad referencial en los identificadores incluidos en la cadena que guarda la jerarquía. Sin embargo, las consultas para obtener los ascendientes, descendientes y realizar una inserción son sencillas.
Las consultas para obtener los ascendientes y los descendientes.
|
|
|
|
Nested Set
La solución de nested set es una solución a las limitaciones del modelo relacional para guardar relaciones jerárquicas. Se basa en añadir a la tabla dos nuevos campos con el rango de nodos contenidos en el nivel inferior.
Esta solución también tiene un modelo de datos sencillo, no requiere tablas adicionales, es fácil de añadir un nuevo nodo a la jerarquía y las consultas para buscar los ascendientes y descendientes son rápidas.
|
|
|
|
Sus desventajas es que no mantiene la integridad referencial. Es más adecuada cuando la estructura de datos no cambia con frecuencia ya que las inserciones y eliminaciones requieren actualizar los valores de los rangos de gran cantidad de nodos. Si se inserta un nuevo nodo en la categoría de procesadores, por ejemplo ARM, su left y right serán 14 y 15 y a todos los right mayor o igual que 14 hay que sumarle más 2.
Para hacer eficientes las consultas que busque nodos inmediatamente inferiores a un determinado nodo requiere añadir una una columna adicional para guardar el nivel del nodo.
Las consultas para obtener los ascendientes, los descendientes y de inserción de un nodo son las siguientes.
|
|
|
|
¿Cúal es la mejor solución para estructuras jerárquicas en bases de datos relacionales?
Si la base de datos soporta consultas recursivas la mejor solución para estructuras jerárquicas en bases de datos relacionales es la de consultas recursivas. Si la base de datos no soporta consultas recursivas la solución de closure table ofrece integridad referencial y es sencilla.
Nested set es adecuada solo sin la estructura de datos jerárquica no cambia con frecuencia y la de adjacency list sin consultas recursivas es adecuada si el rendimiento no es significativo para la aplicación y el nivel de profundidad máximo de la estructura es conocido y está limitado a unos pocos.
Esta es una pequeña comparación entre cada una de las soluciones en su dificultad de implementación y si soporta integridad referencial.