1 votes

Structure de table sans jointure pour les étiquettes

Je travaille sur un petit logiciel de blog, et j'aimerais que des balises soient attachées à un article. Chaque article peut avoir entre 0 et une infinité de balises, et je me demande s'il est possible de faire cela sans avoir à joindre des tables ?

Comme le nombre de balises n'est pas limité, je ne peux pas simplement créer n champs (Tag1 à TagN), donc une autre approche (qui est apparemment celle de StackOverflow) consiste à utiliser un grand champ de texte et un délimiteur, c'est-à-dire "<Tag1><Tag2><Tag3>".

Le problème est là : Si je veux afficher tous les messages contenant une balise, je dois utiliser une instruction "Like '%<Tag2>%'", qui ne peut pas utiliser d'index, ce qui nécessite un balayage complet de la table.

Existe-t-il un moyen approprié de résoudre ce problème ?

Note : Je sais qu'une table Tag-Link séparée présente des avantages et que je ne devrais peut-être pas m'inquiéter des performances sans les mesurer, etc. Je suis plus intéressé par les différentes façons de concevoir un système.

6voto

Ken Keenan Points 5173

Vouloir faire cela sans jointures me semble être une optimisation prématurée. Si cette table est fréquemment consultée, il est très probable que ses pages soient en mémoire et que vous ne subissiez pas de pénalité d'E/S en la lisant, et que les plans des requêtes qui y accèdent soient mis en cache.

3voto

Nico Burns Points 6012

Une table de balises séparée est vraiment la seule façon de procéder ici. C'est LA seule façon d'autoriser un nombre infini de balises.

2voto

IfLoop Points 59461

Cela ressemble à un exercice de dénormalisation. Tout ce qui est vraiment nécessaire est une table qui peut naturellement prendre en charge n'importe quelle requête que vous avez, en répétant toutes les informations que vous devriez autrement joindre à une autre table pour les satisfaire. Une base de données normalisée pour quelque chose comme ce que vous avez pourrait ressembler à ceci :

Posts:
PostID  | PostTitle    | PostBody          | PostAuthor
--------+--------------+-------------------+-------------
1146044 | Join-Free... | I'm working on... | Michael Stum

Tags:
TagID | TagName
------+-------------
1     | Archetecture

PostTags:
PostID  | TagID
--------+------
1146044 | 1

Ensuite, vous pouvez ajouter des colonnes pour optimiser vos requêtes. Si c'était moi, je laisserais probablement la colonne Posts y Tags et d'ajouter des informations supplémentaires dans les PostTags joindre la table. Bien sûr, ce que j'ajoute peut dépendre un peu des requêtes que j'ai l'intention d'exécuter, mais j'ajouterais probablement au moins Posts.PostTitle , Posts.PostAuthor y Tags.TagName de sorte que je n'ai besoin d'exécuter que deux requêtes pour afficher un article de blog,

SELECT * FROM `Posts` WHERE `Posts`.`PostID` = $1 
SELECT * FROM `PostTags` WHERE `PostTags`.`PostID` = $1

Et résumer tous les messages pour un tag donné en demande encore moins,

SELECT * FROM `PostTags` WHERE `PostTags`.`TagName` = $1

Évidemment, l'inconvénient de la dénormalisation est que cela signifie que vous devez faire un peu plus de travail pour maintenir à jour les tables dénormalisées. Une façon typique de gérer ce problème est de mettre en place des contrôles d'intégrité dans votre code qui détectent quand une requête dénormalisée est désynchronisée en la comparant à d'autres informations disponibles. Dans l'exemple ci-dessus, un tel contrôle pourrait consister à comparer les titres des articles dans la base de données de l'utilisateur. PostTags le résultat est comparé au titre dans le Posts résultat. Cela n'entraîne pas de requête supplémentaire. S'il y a une incohérence, le programme peut en informer un administrateur, par exemple en enregistrant l'incohérence ou en envoyant un courriel.

La solution est simple (mais coûteuse en termes de charge de travail du serveur), il suffit de supprimer les colonnes supplémentaires et de les régénérer à partir des tables normalisées. Évidemment, vous ne devriez pas faire cela avant d'avoir trouvé la cause de la désynchronisation de la base de données.

0voto

David Archer Points 954

Si vous utilisez SQL Server, vous pourriez utiliser un champ de texte unique (varchar(max) semble approprié) et une indexation plein texte. Il suffit ensuite d'effectuer une recherche plein texte sur la balise que vous recherchez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X