JSONB avec indexation vs hstore

28

J'essaie de décider de la conception de la base de données, avec le moins d'hypothèses (concernant l'évolution réelle de l'application Web) à ce stade.

Dans un premier temps, sachant que les JOINS sont chers, je considère un petit nombre de tables monolithiques par opposition à un grand nombre de tables plus petites normalisées. Comme deuxième point, je suis confus entre l'utilisation de hstore par rapport aux tables régulières par rapport à JSONB (avec indexation GiST).

AFAIK (n'hésitez pas à corriger):

  1. Généralement, dans Postgres, hstore est connu pour être plus performant que les autres types de données. Cette présentation de FOSDEM PGDAY a des statistiques intéressantes (dans la seconde moitié des diapositives). https://wiki.postgresql.org/images/b/b4/Pg-as-nosql-pgday-fosdem-2013.pdf

  2. Un avantage avec hstore est l'indexation rapide (GiN ou GiST). Cependant, avec JSONB, l'indexation GiN et GiST peut également être appliquée aux données JSON.

  3. Ce blog d'un professionnel du 2nd Quadrant dit "À ce stade, il vaut probablement la peine de remplacer l'utilisation de hstore par jsonb dans toutes les nouvelles applications" (faites défiler jusqu'à la fin): http://blog.2ndquadrant.com/postgresql-anti-patterns-unnecessary -jsonhstore-dynamic-columns /

Je voudrais donc décider de ce qui suit:

  1. Pour la partie principale (structurée) des données: doit-elle aller dans quelques tables relationnelles (relativement grandes avec de nombreuses colonnes), ou doit-elle être un certain nombre de magasins de valeurs-clés utilisant hstore?
  2. Pour les données ad hoc (contribuées par l'utilisateur / non structurées), doivent-elles se trouver dans JSON ou dans des magasins de valeurs de clés ad hoc dans hstore (avec les clés stockées dans l'une des principales tables relationnelles)?
Yogesch
la source
7
Les jointures ne sont pas chères. Qui vous l'a dit? Étant donné que le concept de bases de données relationnelles tourne essentiellement autour des jointures (d'un point de vue pratique), ces produits sont très bons à joindre. La façon de penser normale commence par des structures correctement normalisées et passe à des dénormalisations fantaisistes et autres choses similaires lorsque la performance en a vraiment besoin du côté de la lecture. JSON(B)et hstore(et EAV) conviennent aux données de structure inconnue.
dezso
6
@Yogesch, ces liens contiennent des éléments intéressants et très contradictoires :) Sur le plan moral, il semble que MySQL soit (était) mauvais au niveau des jointures, et les gens de NoSQL ont tendance à généraliser cette notion sans aucune base factuelle réelle. D'un autre côté, Aaron et Max sont sensibles à ce mot p - sa large utilisation montre comment les locuteurs non natifs (moi y compris) utilisent avec bonheur le mauvais mot.
dezso
4
@Yogesch, de façon réaliste, je suis sûr qu'il existe une source sur Internet pour «prouver» quoi que ce soit, tout comme n'importe quel texte religieux peut être utilisé pour justifier des atrocités (comme cela a été dramatiquement démontré à travers l'histoire). Il est vrai que moins vous faites de travail, moins cela coûte, mais il y a toujours un compromis .
Erik
4
@Yogesch: il est important d'éviter les jointures pour les opérations de lecture intensive où vous connaissez à l'avance le modèle d'accès aux données, et vous pouvez donc placer en toute sécurité toutes les données dont vous avez besoin sur une seule ligne. Cependant, cela rend les autres jointures potentiellement plus coûteuses. Qui peut dire que vous n'aurez pas besoin de joindre les données de différentes manières pour répondre à diverses questions? Maintenant, nous allons simplement descendre dans la théorie de la modélisation des données relationnelles ...
Chris
5
@Yogesch Dans ma pratique, avec les bases de données, le goulot d'étranglement est rarement la RAM ou le CPU mais c'est des E / S - de cette façon, éviter de stocker des données redondantes est toujours une chose importante. Comme le dit Chris, si vous voyez toujours vos données d'une seule façon, cela pourrait valoir le prix. Sinon, vous êtes là avec un bloc de données volumineux et très peu flexible.
dezso

Réponses:

41

Les bases de données relationnelles sont conçues autour des jointures et optimisées pour bien les faire.

Sauf si vous avez une bonne raison de ne pas utiliser un design normalisé, utilisez un design normalisé.

jsonbet des choses comme hstoresont bonnes lorsque vous ne pouvez pas utiliser un modèle de données normalisé, comme lorsque le modèle de données change rapidement et est défini par l'utilisateur.

Si vous pouvez le modéliser de manière relationnelle, modélisez-le de manière relationnelle. Si vous ne le pouvez pas, pensez à json, etc. Si vous choisissez entre json / jsonb / hstore, choisissez généralement jsonb, sauf si vous avez une raison de ne pas le faire.

C'est ce que j'ai dit dans mon article de blog , qui ne traite que de ce sujet. Veuillez lire l'intégralité du message . Le paragraphe que vous avez cité souligne que si vous choisissez une structure dynamique, vous devez choisir jsonb plutôt que hstore, mais le reste de l'article de blog explique pourquoi vous devriez généralement préférer modéliser de manière relationnelle si vous le pouvez.

Alors. Modélisez la partie structurée principale de manière relationnelle. Si les tables sont vraiment larges avec beaucoup de colonnes, cela pourrait être un signe qu'une normalisation supplémentaire est nécessaire. N'ayez pas peur des jointures. Apprenez à aimer les jointures. Rejoindre de nombreuses petites tables sera souvent plus rapide que d'interroger et de gérer de grandes tables dénormalisées. Ne dénormalisez que si vous en avez besoin pour des cas spécifiques, et de préférence via des vues matérialisées ... mais ne le faites pas avant de savoir que vous en avez besoin et que vous avez un problème concret à résoudre.

Pour les données fournies par les utilisateurs de forme libre et non structurées, utilisez jsonb. Il devrait fonctionner aussi bien que hstore, mais il est plus flexible et plus facile à utiliser.

Une chose pertinente à comprendre: les index GiST et GIN comme ceux utilisés sur jsonb sont généralement beaucoup moins efficaces qu'un index b-tree simple. Ils sont plus flexibles, mais un index b-tree sur une colonne normale sera presque toujours beaucoup, beaucoup plus rapide.

Craig Ringer
la source
Merci beaucoup Craig, maintenant j'ai une bien meilleure compréhension et je sais quoi faire. Une question de suivi: si je stocke quelque chose comme des likes ou des followers dans un format à deux colonnes (post_id et user_id, pour les likes ), est-il préférable d'utiliser une table relationnelle à deux colonnes ou un hstore? (Cela ne me dérange pas d'en faire une nouvelle question)
Yogesch
5
@Yogesch Cela ressemble à une table de jointure m: n standard avec un format cohérent et stable. La question devrait toujours être "y a-t-il une bonne raison pour laquelle je ne devrais pas faire cela de la manière relationnelle habituelle pour ce cas particulier?".
Craig Ringer
hstoreest obsolète. Utilisez jsonb.
danger89
2
@ danger89 En fait, ce n'est pas formellement obsolète, bien que je ne pense pas qu'il y ait de raison de l'utiliser en faveur de jsonb. En tout cas ... c'est un peu manquer le point. La question est de savoir s'il faut modéliser de manière relationnelle ou utiliser un type de données structuré.
Craig Ringer