Supongamos que estoy construyendo un blog en el que quiero tener publicaciones y comentarios. Por lo tanto, creo dos tablas, una tabla de 'publicaciones' con una columna de 'identificación' de enteros automáticos y una tabla de 'comentarios' que tiene una clave externa 'post_id'.
Luego quiero ejecutar lo que probablemente será mi consulta más común, que es recuperar una publicación y todos sus comentarios. Al ser bastante nuevo en las bases de datos relacionales, el enfoque que me parece más obvio es escribir una consulta que se vería así:
SELECT id, content, (SELECT * FROM comments WHERE post_id = 7) AS comments
FROM posts
WHERE id = 7
Lo que me daría la identificación y el contenido de la publicación que quiero, junto con todas las filas de comentarios relevantes empaquetadas ordenadamente en una matriz (una representación anidada como la que usarías en JSON). Por supuesto, las bases de datos relacionales y SQL no funcionan así, y lo más cerca que pueden estar es hacer una unión entre 'publicaciones' y 'comentarios' que devolverá una gran cantidad de duplicación innecesaria de datos (con la misma información de publicación repetida en cada fila), lo que significa que el tiempo de procesamiento se gasta tanto en la base de datos para poner todo junto como en mi ORM para analizar y deshacer todo.
Incluso si le indico a mi ORM que cargue con entusiasmo los comentarios de la publicación, lo mejor que puede hacer es enviar una consulta para la publicación, y luego una segunda consulta para recuperar todos los comentarios, y luego reunirlos del lado del cliente, que También es ineficiente.
Entiendo que las bases de datos relacionales son tecnología comprobada (demonios, son más antiguas que yo), y que se ha realizado una gran cantidad de investigación a lo largo de las décadas, y estoy seguro de que hay una muy buena razón por la cual ellas (y el SQL estándar) están diseñados para funcionar de la manera en que lo hacen, pero no estoy seguro de por qué el enfoque que describí anteriormente no es posible. Me parece la forma más simple y obvia de implementar una de las relaciones más básicas entre los registros. ¿Por qué las bases de datos relacionales no ofrecen algo como esto?
(Descargo de responsabilidad: principalmente escribo aplicaciones web usando almacenes de datos Rails y NoSQL, pero recientemente he estado probando Postgres, y en realidad me gusta mucho. No quiero atacar bases de datos relacionales, estoy perplejo).
No estoy preguntando cómo optimizar una aplicación Rails, o cómo solucionar este problema en una base de datos en particular. Me pregunto por qué el estándar SQL funciona de esta manera cuando me parece contradictorio y antieconómico. Debe haber alguna razón histórica por la cual los diseñadores originales de SQL querían que sus resultados se vean así.
Respuestas:
CJ Date entra en detalles sobre esto en el Capítulo 7 y el Apéndice B de SQL y Teoría Relacional . Tienes razón, no hay nada en la teoría relacional que prohíba que el tipo de datos de un atributo sea una relación en sí misma, siempre que sea el mismo tipo de relación en cada fila. Su ejemplo calificaría.
Pero Date dice que estructuras como esta están "generalmente, pero no invariablemente, contraindicadas" (es decir, una mala idea) porque las jerarquías de las relaciones son asimétricas . Por ejemplo, una transformación de estructura anidada a una estructura "plana" familiar no siempre se puede revertir para recrear el anidamiento.
Las consultas, restricciones y actualizaciones son más complejas, más difíciles de escribir y más difíciles de admitir para el RDBMS si permite atributos con valor de relación (RVA).
También enturbia los principios de diseño de bases de datos, porque la mejor jerarquía de relaciones no es tan clara. ¿Deberíamos diseñar una relación de Proveedores con un RVA anidado para las piezas suministradas por un Proveedor determinado? ¿O una relación de Partes con un RVA anidado para proveedores que suministran una Parte dada? ¿O almacenar ambos para facilitar la ejecución de diferentes tipos de consultas?
Este es el mismo dilema que resulta de la base de datos jerárquica y los modelos de bases de datos orientados a documentos . Finalmente, la complejidad y el costo de acceder a las estructuras de datos anidados impulsa a los diseñadores a almacenar datos de forma redundante para facilitar la búsqueda por diferentes consultas. El modelo relacional desalienta la redundancia, por lo que los RVA pueden trabajar en contra de los objetivos del modelado relacional.
Por lo que entiendo (no los he usado), Rel y Dataphor son proyectos RDBMS que admiten atributos con valores de relación.
Re comentar de @dportas:
Los tipos estructurados son parte de SQL-99, y Oracle los admite. Pero no almacenan múltiples tuplas en la tabla anidada por fila de la tabla base. El ejemplo común es un atributo de "dirección" que parece ser una sola columna de la tabla base, pero tiene más subcolumnas para calle, ciudad, código postal, etc.
Oracle también admite tablas anidadas , y estas permiten múltiples tuplas por fila de la tabla base. Pero no soy consciente de que esto es parte del SQL estándar. Y tenga en cuenta la conclusión de un blog: "Nunca usaré una tabla anidada en una declaración CREATE TABLE. ¡Dedica todo su tiempo a DESNESTARLOS para que vuelvan a ser útiles!"
fuente
x
puede tener el valor del número entero 42). Las mismas operaciones se aplican a las relaciones y los relvars, por lo que su estructura debe ser compatible.Algunos de los primeros sistemas de bases de datos se basaron en el modelo de base de datos jerárquica . Esto representaba datos en una estructura similar a un árbol con padres e hijos, como sugiere aquí. Los HDMS fueron reemplazados en gran medida por bases de datos basadas en el modelo relacional. Las principales razones de esto fueron que RDBMS podía modelar relaciones "de muchos a muchos" que eran difíciles para las bases de datos jerárquicas y que RDBMS podía realizar fácilmente consultas que no formaban parte del diseño original, mientras que HDBMS lo obligaba a consultar a través de rutas especificadas en tiempo de diseño.
Todavía hay algunos ejemplos de sistemas de bases de datos jerárquicos en la naturaleza, particularmente el registro de Windows y LDAP.
Amplia cobertura de este tema está disponible en el siguiente artículo
fuente
Supongo que su pregunta realmente se centra en el hecho de que, si bien las bases de datos se basan en una lógica sólida y establecen una base teórica y hacen un muy buen trabajo almacenando, manipulando y recuperando datos en conjuntos (bidimensionales) al tiempo que garantizan la integridad referencial, la concurrencia y muchas otras cosas, no proporcionan una característica (adicional) de enviar (y recibir) datos en lo que uno podría llamar formato orientado a objetos o formato jerárquico.
Luego afirma que "incluso si le ordeno a mi ORM que cargue con entusiasmo los comentarios de la publicación, lo mejor que puede hacer es enviar una consulta para la publicación, y luego una segunda consulta para recuperar todos los comentarios, y luego reunirlos del lado del cliente, que también es ineficiente " .
No veo nada ineficiente en enviar 2 consultas y recibir 2 lotes de resultados con:
Yo diría que es (casi) la forma más eficiente (casi, ya que realmente no necesita las
posts.id
columnas y no todascomments.*
)Como Todd señaló en su comentario, no debe pedirle a la base de datos que devuelva datos listos para mostrar. Es el trabajo de la aplicación hacer eso. Puede escribir (una o algunas) consultas para obtener los resultados que necesita para cada operación de visualización para que no haya duplicación innecesaria en los datos enviados a través del cable (o el bus de memoria) desde la base de datos a la aplicación.
Realmente no puedo hablar de ORM, pero quizás algunos de ellos puedan hacer parte de este trabajo por nosotros.
Se pueden utilizar técnicas similares en la entrega de datos entre un servidor web y un cliente. Se utilizan otras técnicas (como el almacenamiento en caché) para que la base de datos (o la web u otro servidor) no se sobrecargue con solicitudes duplicadas.
Supongo que los estándares, como SQL, son mejores si permanecen especializados en un área y no intentan cubrir todas las áreas de un campo.
Por otro lado, el comité que establece el estándar SQL bien puede pensar lo contrario en el futuro y proporcionar estandarización para una característica adicional. Pero no es algo que se pueda diseñar en una noche.
fuente
No puedo responder con una respuesta adecuada y discutida, así que siéntase libre de votarme en el olvido si me equivoco (pero corríjame para que podamos aprender algo nuevo). Creo que la razón es que las bases de datos relacionales se centran en el modelo relacional, que a su vez se basa en algo de lo que no sé nada llamado "lógica de primer orden". Lo que puede preguntar probablemente no encaja conceptualmente en el marco matemático / lógico sobre el que se basan las bases de datos relacionales. Además, lo que pides generalmente se resuelve fácilmente mediante bases de datos de gráficos, lo que da más pistas de que es la conceptualización subyacente de la base de datos lo que está en conflicto con lo que quieres lograr.
fuente
Sé que al menos SQLServer admite consultas anidadas cuando usas FOR XML.
El problema aquí no es la falta de soporte del RDBMS, sino la falta de soporte de tablas anidadas en tablas.
Además, ¿qué te impide usar una unión interna?
Puede ver la unión interna como una tabla anidada, solo el contenido de los primeros 2 campos se repite una vez. No me preocuparía mucho el rendimiento de la combinación, la única parte lenta en una consulta como esta es la io desde la base de datos hasta el cliente. Esto solo será un problema cuando el contenido contenga una gran cantidad de datos. En ese caso, sugeriría dos consultas, una con
select id, content
y una con una combinación interna yselect posts.id, comments.*
. Esto se escala incluso con varias publicaciones, ya que solo usaría 2 consultas.fuente
for xml
.En realidad, Oracle admite lo que desea, pero debe ajustar la subconsulta con la palabra clave "cursor". Los resultados se obtienen a través del cursor abierto. En Java, por ejemplo, los comentarios aparecerían como conjuntos de resultados. Más sobre esto, vea la documentación de Oracle sobre "CURSOR Expression"
fuente
Algunos admiten el anidamiento (jerárquico).
Si quisiera una consulta, podría tener una tabla que se haga referencia a sí misma. Algunos RDMS apoyan este concepto. Por ejemplo, con SQL Server se pueden usar expresiones de tabla comunes (CTE) para una consulta jerárquica.
En su caso, las Publicaciones estarían en el Nivel 0 y luego todos los comentarios estarían en el Nivel 1.
Las otras opciones son 2 consultas o Unirse con información adicional para cada registro devuelto (que otros han mencionado).
Ejemplo de jerárquico:
https://stackoverflow.com/questions/14274942/sql-server-cte-and-recursion-example
En el enlace anterior, EmpLevel muestra el nivel de anidamiento (o jerarquía).
fuente
Lo siento, no estoy seguro de entender su problema exactamente.
En MSSQL solo puede ejecutar 2 declaraciones SQL.
Y devolverá sus 2 conjuntos de resultados simultáneamente.
fuente
Los RDBM se basan en la teoría y se adhieren a la teoría. Esto permite una buena consistencia y una confiabilidad matemáticamente probada.
Debido a que el modelo es simple y nuevamente basado en la teoría, facilita a las personas la optimización y muchas implementaciones. Esto es diferente a NoSQL donde todos lo hacen ligeramente diferente.
En el pasado hubo intentos de crear bases de datos jerárquicas, pero el IIRC (parece que no puede googlearlo) ha habido problemas (ciclos e igualdad vienen a mi mente).
fuente
Tienes una necesidad específica. Sería preferible extraer datos de una base de datos en el formato que desee, para que pueda hacer con él lo que desee.
Algunas cosas que las bases de datos no hacen tan bien, pero no es imposible construirlas para hacerlo de todos modos. Dejar el formato a otras aplicaciones es la recomendación actual, pero no justifica por qué no se puede hacer.
El único argumento que tengo en contra de su sugerencia es poder manejar este conjunto de resultados de una manera "sql". Sería una mala idea crear un resultado en la base de datos y no poder trabajar con él o manipularlo hasta cierto punto. Digamos que creé una vista construida de la manera que sugieres, ¿cómo la incluyo en otra declaración select? A las bases de datos les gusta tomar resultados y hacer cosas con ellos. ¿Cómo lo uniría a otra mesa? ¿Cómo compararía su conjunto de resultados con otro?
Entonces el beneficio de RDMS es la flexibilidad de sql. La sintaxis para seleccionar datos de una tabla está bastante cerca de una lista de usuarios u otros objetos en el sistema (al menos ese es el objetivo). No estoy seguro de que tenga sentido hacer algo completamente diferente. Ni siquiera los han llevado al punto de manejar código / cursores de procedimiento o BLOBS de datos de manera muy eficiente.
fuente
En mi opinión, se debe principalmente a SQL y a la forma en que se realizan las consultas agregadas: las funciones agregadas y la agrupación se ejecutan en grandes conjuntos de filas bidimensionales para devolver resultados. Así ha sido desde el principio y es muy rápido (la mayoría de las soluciones NoSQL son bastante lentas con la agregación y dependen del esquema desnormalizado en lugar de consultas complejas)
Por supuesto, PostgreSQL tiene algunas características de la base de datos orientada a objetos. De acuerdo con este correo ( mensaje ), puede lograr lo que necesita creando un agregado personalizado.
Personalmente, estoy usando marcos como Doctrine ORM (PHP) que hacen la agregación del lado de la aplicación y admiten características como la carga diferida para aumentar el rendimiento.
fuente
PostgreSQL admite una variedad de tipos de datos estructurados, incluidos Arrays y JSON . Con SQL o uno de los lenguajes de procedimiento integrados, puede crear valores con una estructura arbitrariamente compleja y devolverlos a su aplicación. También puede crear tablas con columnas de cualquiera de los tipos estructurados, aunque debe considerar cuidadosamente si está desnormalizando innecesariamente su diseño.
fuente