Mysql
 sql >> Base de données >  >> RDS >> Mysql

mysql :utiliser SET ou beaucoup de colonnes ?

Il semble que vous soyez principalement préoccupé par les performances.

Quelques personnes ont suggéré de diviser en 3 tables (table de catégories plus une simple table de références croisées ou une manière plus sophistiquée de modéliser la hiérarchie arborescente, comme un ensemble imbriqué ou un chemin matérialisé), ce qui est la première chose à laquelle j'ai pensé quand j'ai lu votre question .

Avec les index, une approche entièrement normalisée comme celle-ci (qui ajoute deux JOIN) aura toujours de "assez bonnes" performances de lecture. Un problème est qu'un INSERT ou UPDATE à un événement peut maintenant également inclure un ou plusieurs INSERT/UPDATE/DELETE dans la table de références croisées, ce qui sur MyISAM signifie que la table de références croisées est verrouillée et sur InnoDB signifie que les lignes sont verrouillées, donc si votre base de données est occupée par un nombre important d'écritures, vous aurez des problèmes de contention plus importants que si seules les lignes d'événement étaient verrouillées.

Personnellement, j'essaierais cette approche entièrement normalisée avant d'optimiser. Mais, je suppose que vous savez ce que vous faites, que vos hypothèses sont correctes (les catégories ne changent jamais) et que vous avez un modèle d'utilisation (beaucoup d'écritures) qui nécessite une structure plate moins normalisée. C'est très bien et cela fait partie de ce qu'est NoSQL.

SET contre "beaucoup de colonnes"

Donc, en ce qui concerne votre question "SET vs beaucoup de colonnes", je peux dire que j'ai travaillé avec deux entreprises avec des ingénieurs intelligents (dont les produits étaient des applications Web CRM... l'un était en fait la gestion d'événements), et ils ont tous les deux utilisé l'approche "beaucoup de colonnes" pour ce type de données d'ensemble statique.

Mon conseil serait de penser à toutes les requêtes que vous ferez sur cette table (pondérées par leur fréquence) et au fonctionnement des index.

Tout d'abord, avec l'approche "beaucoup de colonnes", vous allez avoir besoin d'index sur chacune de ces colonnes afin de pouvoir effectuer des événements SELECT FROM events WHERE CategoryX = TRUE . Avec les index, c'est une requête ultra-rapide.

Par rapport à SET, vous devez utiliser AND (&), LIKE ou FIND_IN_SET() au niveau du bit pour effectuer cette requête. Cela signifie que la requête ne peut pas utiliser d'index et doit effectuer une recherche linéaire de toutes les lignes (vous pouvez utiliser EXPLAIN pour le vérifier). Requête lente !

C'est la principale raison pour laquelle SET est une mauvaise idée - son index n'est utile que si vous sélectionnez par groupes exacts de catégories. SET fonctionne très bien si vous sélectionnez des catégories par événement, mais pas l'inverse.

Le principal problème avec l'approche "beaucoup de colonnes" moins normalisée (par opposition à une approche entièrement normalisée) est qu'elle ne s'adapte pas. Si vous avez 5 catégories et qu'elles ne changent jamais, très bien, mais si vous en avez 500 et que vous les modifiez, c'est un gros problème. Dans votre scénario, avec environ 30 qui ne changent jamais, le principal problème est qu'il y a un index sur chaque colonne, donc si vous effectuez des écritures fréquentes, ces requêtes deviennent plus lentes en raison du nombre d'index qui doivent être mis à jour. Si vous choisissez cette approche, vous voudrez peut-être consulter le journal des requêtes lentes de MySQL pour vous assurer qu'il n'y a pas de requêtes lentes aberrantes en raison de conflits aux heures de pointe de la journée.

Dans votre cas, si la vôtre est une application Web typique à forte intensité de lecture, je pense qu'il est probablement sensé d'adopter l'approche "beaucoup de colonnes" (comme l'ont fait les deux produits CRM, pour la même raison). C'est certainement plus rapide que SET pour cette requête SELECT.

TL;DR N'utilisez pas SET car la requête "sélectionner les événements par catégorie" sera lente.