Supposons que je construise un blog pour lequel je souhaite avoir des posts et des commentaires. Je crée donc deux tables, une table 'posts' avec une colonne 'id' entier auto-incrémentée et une table 'commentaires' avec une clé étrangère 'post_id'.
Ensuite, je veux exécuter ce qui sera probablement ma requête la plus courante, qui consiste à récupérer un message et tous ses commentaires. Étant assez nouveau dans les bases de données relationnelles, l’approche qui me semble la plus évidente consiste à écrire une requête qui ressemblerait à quelque chose comme:
SELECT id, content, (SELECT * FROM comments WHERE post_id = 7) AS comments
FROM posts
WHERE id = 7
Ce qui me donnerait l'identifiant et le contenu de la publication que je veux, ainsi que toutes les lignes de commentaires pertinentes, parfaitement regroupées dans un tableau (une représentation imbriquée comme celle que vous utiliseriez dans JSON). Bien sûr, SQL et les bases de données relationnelles ne fonctionnent pas ainsi, et le plus proche possible est de faire une jointure entre 'posts' et 'comments' qui renverra beaucoup de duplications inutiles de données (avec les mêmes informations postées répétées). dans chaque ligne), ce qui signifie que le temps de traitement est consacré à la fois à la base de données pour tout rassembler et à mon ORM pour analyser et annuler le tout.
Même si j'ordonne à mon ORM de charger avec empressement les commentaires de l'article, le mieux consiste à envoyer une requête pour l'article, puis une seconde requête pour extraire tous les commentaires, puis de les assembler côté client, qui est également inefficace.
Je comprends que les bases de données relationnelles sont une technologie éprouvée (diable, elles sont plus vieilles que moi), et qu’elles ont fait l’objet de nombreuses recherches au cours des décennies, et je suis sûr qu’il ya une très bonne raison pour laquelle elles (et le SQL) sont conçus pour fonctionner comme ils le font, mais je ne sais pas pourquoi la démarche que je viens de décrire est impossible. Cela me semble être le moyen le plus simple et le plus évident d'implémenter l'une des relations les plus fondamentales entre les enregistrements. Pourquoi les bases de données relationnelles n'offrent-elles pas quelque chose comme ça?
(Avertissement: j'écris principalement des applications Web à l'aide de bases de données Rails et NoSQL, mais j'ai récemment essayé Postgres et je l'aime beaucoup. Je ne veux pas attaquer les bases de données relationnelles, je suis perplexe.)
Je ne vous demande pas comment optimiser une application Rails ou comment résoudre ce problème dans une base de données particulière. Je demande pourquoi le standard SQL fonctionne de cette façon quand il me semble contre-intuitif et inutile. Il doit exister une raison historique pour laquelle les concepteurs originaux de SQL voulaient que leurs résultats ressemblent à ceci.
Réponses:
CJ Date va plus en détail à ce sujet au chapitre 7 et à l’annexe B de SQL et de la théorie relationnelle . Vous avez raison, rien dans la théorie relationnelle n'interdit au type de données d'un attribut d'être une relation en tant que telle, à condition qu'il s'agisse du même type de relation sur chaque ligne. Votre exemple serait admissible.
Mais Date indique que de telles structures sont "généralement - mais pas invariablement - contre-indiquées" (c’est-à-dire une mauvaise idée) car les hiérarchies des relations sont asymétriques . Par exemple, une transformation d'une structure imbriquée en une structure "plate" familière ne peut pas toujours être inversée pour recréer l'imbrication.
Les requêtes, les contraintes et les mises à jour sont plus complexes, plus difficiles à écrire et à prendre en charge par le SGBDR si vous autorisez des attributs à valeur relationnelle (RVA).
Cela brouille également les principes de conception des bases de données, car la meilleure hiérarchie des relations n’est pas aussi claire. Devrions-nous concevoir une relation de fournisseurs avec une RVA imbriquée pour les pièces fournies par un fournisseur donné? Ou une relation de pièces avec une RVA imbriquée pour les fournisseurs qui fournissent une pièce donnée? Ou bien stocker les deux pour faciliter l’exécution de différents types de requêtes?
C'est le même dilemme qui découle des modèles de base de données hiérarchique et de base de données orientée document . Finalement, la complexité et le coût d’accès aux structures de données imbriquées incitent les concepteurs à stocker les données de manière redondante pour faciliter la recherche par différentes requêtes. Le modèle relationnel déconseillant la redondance, les RVA peuvent donc aller à l'encontre des objectifs de la modélisation relationnelle.
D'après ce que j'ai compris (je ne les ai pas utilisés), Rel et Dataphor sont des projets de SGBDR qui prennent en charge des attributs à valeur relationnelle.
Commentaire de @dportas:
Les types structurés font partie de SQL-99 et Oracle les prend en charge. Mais ils ne stockent pas plusieurs tuples dans la table imbriquée par ligne de la table de base. L'exemple courant est un attribut "adresse" qui semble être une colonne unique de la table de base, mais comporte d'autres sous-colonnes pour la rue, la ville, le code postal, etc.
Les tables imbriquées sont également prises en charge par Oracle. Celles-ci permettent plusieurs nuplets par ligne de la table de base. Mais je ne suis pas au courant que cela fait partie du SQL standard. Et gardez à l'esprit la conclusion d'un blog: "Je n'utiliserai jamais une table imbriquée dans une instruction CREATE TABLE. Vous passez tout votre temps à les NESTIVER pour les rendre utiles à nouveau!"
la source
x
peut avoir la valeur de 42). Les mêmes opérations s'appliquent aux relations et aux commentaires, de sorte que leur structure doit être compatible.Certains des systèmes de base de données les plus anciens étaient basés sur le modèle de base de données hiérarchique . Cela représentait des données dans une arborescence ressemblant à une structure avec parent et enfants, un peu comme vous le suggérez ici. Les HDMS ont été largement remplacés par des bases de données construites sur le modèle relationnel. Les principales raisons en étaient que le SGBDR pouvait modéliser des relations "nombreuses à multiples" difficiles pour les bases de données hiérarchiques et qu'il pouvait facilement exécuter des requêtes ne faisant pas partie de la conception d'origine alors que HDBMS vous obligeait à interroger des chemins spécifiés au moment de la conception.
Il existe encore quelques exemples de systèmes de bases de données hiérarchiques, notamment le registre Windows et LDAP.
Une vaste couverture de ce sujet est disponible dans l' article suivant
la source
Je suppose que votre question porte en réalité sur le fait que, même si les bases de données reposent sur une logique et des bases théoriques solides, elles stockent, manipulent et extraient les données dans des ensembles (à deux dimensions) tout en garantissant l’intégrité référentielle, la simultanéité et bien d’autres choses encore, ils ne fournissent pas une fonctionnalité (supplémentaire) d’envoi (et de réception) de données dans ce que l’on pourrait appeler un format orienté objet ou un format hiérarchique.
Ensuite, vous déclarez que "même si je demande à mon ORM de charger avec empressement les commentaires de l'article, le mieux qu'il puisse faire est d'envoyer une requête pour l'article, puis une deuxième requête pour extraire tous les commentaires, puis les assembler côté client, ce qui est également inefficace " .
Je ne vois rien d’inefficace dans l’envoi de 2 requêtes et la réception de 2 lots de résultats avec:
Je dirais que c'est (presque) le moyen le plus efficace (presque, car vous n'avez pas vraiment besoin de la
posts.id
colonne et pas de toutes les colonnescomments.*
)Comme Todd l'a souligné dans son commentaire, vous ne devriez pas demander à la base de données de renvoyer des données prêtes à être affichées. C'est le travail de l'application de le faire. Vous pouvez écrire (une ou plusieurs) requêtes pour obtenir les résultats dont vous avez besoin pour chaque opération d'affichage afin d'éviter toute duplication inutile des données envoyées sur le réseau (ou le bus de mémoire) de la base de données vers l'application.
Je ne peux pas vraiment parler des ORM mais peut-être que certains d’entre eux peuvent faire partie de ce travail pour nous.
Des techniques similaires peuvent être utilisées pour la transmission de données entre un serveur Web et un client. D'autres techniques (comme la mise en cache) sont utilisées pour que la base de données (ou le serveur Web ou un autre serveur) ne soit pas surchargée de demandes en double.
Je suppose que les normes, comme SQL, sont préférables si elles restent spécialisées dans un domaine et n'essayent pas de couvrir tous les domaines d'un domaine.
D'autre part, le comité qui établit la norme SQL pourrait bien penser le contraire à l'avenir et fournir la normalisation d'une telle fonctionnalité supplémentaire. Mais ce n'est pas quelque chose qui peut être conçu en une nuit.
la source
Je ne suis pas en mesure de répondre avec une réponse correcte et argumentée, alors n'hésitez pas à me laisser tomber dans l'oubli si je me trompe (mais corrigez-moi afin que nous puissions apprendre quelque chose de nouveau). Je pense que la raison en est que les bases de données relationnelles sont centrées sur le modèle relationnel, qui à son tour est basé sur quelque chose que je ne connais pas, appelé "logique du premier ordre". Ce que vous demandez peut-être ne correspond probablement pas au cadre mathématique / logique sur lequel reposent les bases de données relationnelles. De plus, ce que vous demandez est généralement résolu facilement par les bases de données graphiques, ce qui donne plus d'indications sur le fait que c'est la conceptualisation sous-jacente de la base de données qui est en conflit avec ce que vous souhaitez réaliser.
la source
Je sais au moins que SQLServer prend en charge les requêtes imbriquées lorsque vous utilisez FOR XML.
Le problème ici n'est pas le manque de support du SGBDR, mais le manque de support des tables imbriquées dans les tables.
De plus, qu'est-ce qui vous empêche d'utiliser une jointure interne?
Vous pouvez voir la jointure interne comme une table imbriquée, seul le contenu des 2 premiers champs est répété une fois. Je ne m'inquiéterais pas beaucoup des performances de la jointure, le seul élément lent d'une requête comme celle-ci est l'io de la base de données au client. Cela ne posera problème que lorsque le contenu contient une grande quantité de données. Dans ce cas, je suggérerais deux requêtes, une avec
select id, content
et une avec une jointure interne etselect posts.id, comments.*
. Cela évolue même avec plusieurs publications, car vous n'utiliseriez toujours que 2 requêtes.la source
for xml
.En réalité, Oracle prend en charge ce que vous voulez, mais vous devez envelopper la sous-requête avec le mot clé "cursor". Les résultats sont récupérés via le curseur ouvert. En Java, par exemple, les commentaires apparaissent sous forme de jeux de résultats. Pour plus d'informations, consultez la documentation d'Oracle sur "CURSOR Expression".
la source
Certains supportent l'imbrication (hiérarchique).
Si vous voulez une requête, vous pouvez avoir une table qui se référence elle-même. Certains RDMS supportent ce concept. Par exemple, avec SQL Server, vous pouvez utiliser des expressions de table communes (CTE) pour une requête hiérarchique.
Dans votre cas, les messages seraient au niveau 0 et tous les commentaires seraient au niveau 1.
Les autres options sont 2 requêtes ou une jointure avec des informations supplémentaires pour chaque enregistrement renvoyé (mentionné par d'autres).
Exemple de hiérarchie:
https://stackoverflow.com/questions/14274942/sql-server-cte-and-recursion-example
Dans le lien ci-dessus, EmpLevel indique le niveau d'imbrication (ou de hiérarchie).
la source
Je suis désolé, je ne suis pas sûr de bien comprendre votre problème.
Dans MSSQL, vous pouvez simplement exécuter 2 instructions SQL.
Et il retournera vos 2 jeux de résultats simultanément.
la source
Les RDBM sont basés sur la théorie et ils s'en tiennent à la théorie. Cela permet une certaine cohérence et une fiabilité mathématiquement prouvée.
Parce que le modèle est simple et basé à nouveau sur la théorie, il est facile pour les personnes d’optimiser et de nombreuses implémentations. Ceci est différent de NoSQL où tout le monde le fait légèrement différemment.
Il y a eu des tentatives dans le passé pour créer des bases de données hiérarchiques, mais l'IIRC (semble ne pas vouloir le chercher sur Google), mais des problèmes se sont posés (des cycles et l'égalité nous viennent à l'esprit).
la source
Vous avez un besoin spécifique. Il serait préférable d'extraire les données d'une base de données dans le format de votre choix afin de pouvoir en faire ce que vous voulez.
Certaines choses que les bases de données ne font pas aussi bien, mais il n'est pas impossible de les construire pour le faire de toute façon. Laisser la formation à d’autres applications est la recommandation actuelle, mais ne justifie pas pourquoi cela ne peut pas être fait.
Le seul argument que j'ai contre votre suggestion est de pouvoir traiter ce résultat avec "sql". Ce serait une mauvaise idée de créer un résultat dans la base de données et de ne pas pouvoir l'utiliser ou la manipuler dans une certaine mesure. Supposons que j'ai créé une vue construite à la manière que vous suggérez, comment l'inclure dans une autre instruction select? Les bases de données aiment prendre des résultats et faire des choses avec eux. Comment pourrais-je le joindre à une autre table? Comment pourrais-je comparer votre jeu de résultats à un autre?
Alors, l'avantage de RDMS est la flexibilité de SQL. La syntaxe de sélection des données d'une table est assez proche de celle d'une liste d'utilisateurs ou d'autres objets du système (c'est du moins l'objectif). Pas sûr qu'il soit utile de faire quelque chose de complètement différent. Ils ne les ont même pas amenés au point de gérer très efficacement le code de procédure / les curseurs ou les BLOBS de données.
la source
À mon avis, c'est principalement à cause de SQL et de la manière dont les requêtes d'agrégat sont effectuées - les fonctions d'agrégat et le regroupement sont exécutés sur de grands ensembles de lignes bidimensionnels pour renvoyer les résultats. C'est comme ça depuis le début et c'est très rapide (la plupart des solutions NoSQL sont assez lentes avec l'agrégation et reposent sur un schéma dénormalisé au lieu de requêtes complexes)
Bien sûr, PostgreSQL a quelques fonctionnalités de base de données orientée objet. Selon ce courrier ( message ), vous pouvez obtenir ce dont vous avez besoin en créant un agrégat personnalisé.
Personnellement, j'utilise des frameworks tels que Doctrine ORM (PHP) qui effectuent l'agrégation côté application et prennent en charge des fonctionnalités telles que le chargement différé pour augmenter les performances.
la source
PostgreSQL prend en charge une variété de types de données structurés, notamment les tableaux et JSON . À l'aide de SQL ou de l'un des langages procéduraux intégrés, vous pouvez créer des valeurs avec une structure arbitrairement complexe et les renvoyer à votre application. Vous pouvez également créer des tableaux avec des colonnes de n'importe quel type structuré, bien que vous deviez vérifier si vous dénormalisez inutilement votre conception.
la source