Utilisez MySQL pour effectuer régulièrement des jointures multidirectionnelles sur des tables de plus de 100 Go?


11

Contexte :
J'ai créé une application Web que j'aimerais pouvoir évoluer raisonnablement bien. Je sais que je ne suis pas Google ou Twitter, mais mon application utilise une quantité assez importante de données pour chaque utilisateur et a donc des exigences de données assez élevées. Je veux être prêt à évoluer raisonnablement bien sans avoir à tout ré-architecturer plus tard.

Je me considère comme un développeur de logiciels, pas un expert en bases de données. C'est pourquoi je poste ici. J'espère que quelqu'un avec beaucoup plus d'expertise en base de données pourra me donner des conseils.

Avec un nombre d'utilisateurs relativement important, mais rien de tel que les numéros Facebook, je m'attends à avoir une base de données qui ressemble à ceci:

Une "grande table":

  • 250 millions d'enregistrements
  • 20 colonnes
  • Environ 100 Go de données
  • Dispose d'une clé étrangère bigint indexée (20)
  • A une colonne varchar (500) indexée string_id
  • A une colonne int (11) "value"

4 autres tables:

  • 10 millions d'enregistrements chacun
  • Environ 2 à 4 Go de données chacun
  • chacun de ces tableaux comprend 4 à 8 colonnes
  • une colonne est datetime date_created
  • une colonne est la colonne varchar (500) string_id
  • une ou deux colonnes de chacune de ces tables seront sélectionnées dans une jointure

L'une de ces tables est utilisée pour stocker des moyennes - son schéma est bigint (20) id, varchar (20) string_id, datetime date_created, float average_value

Ce que je veux faire - deux requêtes relativement coûteuses:

  1. Calculez de nouvelles valeurs moyennes:

    • À l'aide d'une clé étrangère, sélectionnez jusqu'à plusieurs millions d'enregistrements distincts dans la grande table.
    • Calculez une nouvelle moyenne, regroupée par string_id.
    • Insérez les résultats dans le tableau des moyennes.
    • Telle qu'elle est actuellement construite, cette requête utilise deux jointures.
  2. Créez des enregistrements en lecture seule dénormalisés pour les utilisateurs au service:

    • Utilisez une clé étrangère pour sélectionner entre 1 000 et 40 000 enregistrements dans la grande table.
    • Joignez-vous à chacune des quatre autres tables de l'enregistrement le plus récent avec la colonne id chaîne.
    • Insérez les résultats dans un tableau dénormalisé.
    • Ces enregistrements sont destinés au front-end pour afficher des informations aux utilisateurs.
    • Telle qu'elle est actuellement construite, cette requête utilise quatre jointures.

Je prévois d'exécuter chacune de ces requêtes coûteuses sur une base de données principale par lots qui transmettra ses résultats à un serveur de base de données frontal en temps réel qui gère les demandes des utilisateurs. Ces requêtes seront exécutées à intervalles réguliers. Je n'ai pas décidé combien de fois. La requête moyenne pourrait être effectuée peut-être une fois par jour. La requête de dénormalisation devra être plus fréquente, peut-être toutes les quelques minutes.

Chacune de ces requêtes s'exécute actuellement en quelques secondes dans MySQL sur une machine très bas de gamme avec un ensemble de données avec 100 000 enregistrements dans la «grande table». Je m'inquiète à la fois de ma capacité à évoluer et des coûts de l'évolutivité.

Questions :

  1. Cette approche semble-t-elle judicieuse? Y a-t-il quelque chose de mal à l'évidence du point de vue global?
  2. Un SGBDR est-il le bon outil, ou devrais-je envisager d'autres solutions de "big data" comme quelque chose dans la famille Hadoop? Mon inclination est d'utiliser un SGBDR car les données sont structurées et s'intègrent bien dans le modèle relationnel. À un certain moment cependant, je crois comprendre que je ne pourrai peut-être plus utiliser un SGBDR. Est-ce vrai? Quand ce commutateur serait-il nécessaire?
  3. Est-ce que ça marchera? Ces requêtes peuvent-elles être exécutées dans un délai raisonnable? Je peux attendre peut-être des heures pour la requête # 1, mais la requête # 2 devrait se terminer en quelques minutes.
  4. Que dois-je considérer du point de vue matériel? Quels sont les goulots d'étranglement RAM et CPU susceptibles d'être? Je suppose que la conservation des index dans la RAM est importante. Y a-t-il autre chose que je devrais considérer?
  5. À un moment donné, je devrai probablement partitionner mes données et utiliser plusieurs serveurs. Mon cas d'utilisation semble-t-il être déjà dans cette catégorie, ou vais-je être capable de faire évoluer une seule machine verticalement pendant un certain temps? Est-ce que cela fonctionnera avec 10 fois les données? 100x?

Celui-ci est difficile à répondre à fond. Peut-être que vous feriez mieux de faire des recherches sur les caractéristiques de performance des requêtes MySQL en général afin de savoir à quoi vous attendre. Une chose que vous pouvez toujours faire bien sûr est de mettre 20 disques dans le serveur afin que vous puissiez lire à 3 Go / s environ. Mais je pense que vous recherchez une réponse complète uniquement logicielle.
usr

Réponses:


4

Avez-vous essayé d'empiler plus de données et de les comparer? 100K lignes est sans conséquence. Essayez 250M ou 500M comme si vous vous attendiez à devoir gérer et voir où se trouvent les goulots d'étranglement.

Un SGBDR peut faire beaucoup de choses si vous portez une attention particulière aux limites et essayez de travailler avec les points forts du système. Ils sont exceptionnellement bons dans certaines choses et terribles dans d'autres, vous devrez donc expérimenter pour vous assurer que c'est le bon ajustement.

Pour certains travaux de traitement par lots, vous ne pouvez vraiment pas battre des fichiers plats, charger les données dans la RAM, les écraser à l'aide d'une série de boucles et de variables temporaires et vider les résultats. MySQL ne pourra jamais, jamais égaler ce genre de vitesse, mais s'il est réglé correctement et utilisé correctement, il peut entrer dans un ordre de grandeur.

Ce que vous voudrez faire, c'est étudier comment vos données peuvent être partitionnées. Avez-vous un grand ensemble de données avec trop de liens croisés pour pouvoir le diviser, ou y a-t-il des endroits naturels pour le partitionner? Si vous pouvez le partitionner, vous n'aurez pas une table avec une pile entière de lignes, mais potentiellement beaucoup plus petites. Les tables plus petites, avec des index beaucoup plus petits, ont tendance à mieux fonctionner.

Du point de vue matériel, vous devrez tester pour voir comment votre plate-forme fonctionne. Parfois, la mémoire est essentielle. D'autres fois, il s'agit d'E / S disque. Cela dépend vraiment de ce que vous faites avec les données. Vous devrez faire très attention à l'utilisation de votre processeur et rechercher des niveaux élevés d'E / S pour savoir où se situe le problème.

Dans la mesure du possible, divisez vos données sur plusieurs systèmes. Vous pouvez utiliser MySQL Cluster si vous vous sentez courageux, ou simplement créer de nombreuses instances indépendantes de MySQL où chacune stocke une partie arbitraire de l'ensemble de données complet en utilisant un schéma de partitionnement qui a du sens.


@tadman Merci pour vos conseils. Je me rends compte qu'il n'y a pas de substitut à l'essayer. Je ne l'ai pas comparé avec 250 millions de lignes parce que je voulais d'abord m'assurer qu'il n'y avait rien de mal à propos de mon approche. Il semble qu'il n'y en ait pas. De plus, obtenir autant de données et le faire d'une manière quelque peu réaliste est un défi que je n'ai pas encore trouvé de solution. J'ai quelques moyens potentiels de partitionner les données. Je suppose que je vais ensuite essayer d'augmenter mes données et voir comment cela se passe à différents points de contrôle - 1M, 10M, 100M, etc.
xnickmx

1

Tableaux récapitulatifs.

Chaque jour, calculez des informations agrégées pour les données de la journée. Mettez cela dans le (s) tableau (s) "récapitulatif (s)". Faites vos requêtes contre eux. 10 fois plus rapide.

Pour plus de discussion, veuillez fournir

  • AFFICHER CRÉER UN TABLEAU (tel qu'il est actuellement)
  • Tailles de table (que vous avez mentionnées)
  • SELECTs proposés

Quelques choses évidentes ...

  • BIGINT est rarement garanti. Cela prend 8 octets. INT UNSIGNED prend 4 et autorise des valeurs de 0 à 4 milliards. Et il y a MEDIUMINT, etc.
  • Plusieurs index sur la table des «faits» sont généralement un grave problème de performances, en particulier pour les INSERT. Avez-vous un problème là-bas?
  • DATETIME est de 8 octets; TIMESTAMP est 4
  • Les CONTRAINTES CLÉS ÉTRANGÈRES explicites sont agréables, mais coûteuses
  • JOINs peut ou non être un problème de performances; besoin de voir les SELECT et CREATEs.
  • 100 Go est une bonne taille pour une «grande» base de données MySQL; Je soupçonne que cela pourrait fonctionner sans Hadoop, etc.
  • Allez-vous «purger» les données à un moment donné? (Cela conduit au cas d'utilisation principal du PARTITIONnement.)

"Plus petit -> plus cacheable -> plus rapide


0

Pour servir vos données frontales, à moins qu'il n'y ait des gobs et des gobs d'inserts tout le temps, vous ne pouvez vraiment pas battre en utilisant des déclencheurs pour insérer dans des vues matérialisées qui sont synchronisées avec le back-end mais optimisées pour servir les données. Bien sûr, vous devez réduire au minimum les jointures, etc., etc. dans ces déclencheurs. Une stratégie que j'ai utilisée consiste à mettre ces insertions / mises à jour en file d'attente dans une table intermédiaire, puis à les envoyer plus tard toutes les minutes environ. Il est beaucoup plus facile d'envoyer un enregistrement que 4 Go d'enregistrements. 4 Go de données prennent beaucoup de temps à diffuser même si vous pouvez trouver rapidement les enregistrements que vous recherchez.

Je suis d'accord avec Tadman. Le mieux est de le profiler avec le type de données que vous attendez sur le type de système que vous recherchez.


Comme je l'ai mentionné dans mon article, les vues dépendent d'une requête qui utilise quatre jointures sur des tables avec des dizaines de millions d'enregistrements, donc je ne vois pas vraiment comment une vue matérialisée va aider.
xnickmx

Les déclencheurs peuvent ne pas être assez rapides pour cette base de données de taille. Combien d'insertions se produisent par seconde?
Rick James

1
@xnickmx S'il n'y a pas autant d'insertions / mises à jour, les déclencheurs permettent de synchroniser facilement / efficacement les données dénormalisées. S'il doit aller plus vite pour les insertions / mises à jour, mettez-les en file d'attente avec quelque chose comme ceci: blog.shlomoid.com/2008/04/… ou faites-en votre propre. De cette façon, vous n'avez pas à vous joindre aux 100 millions de tables de lignes existantes pour obtenir les nouvelles données, car lorsque le déclencheur se déclenche, vous profitez du fait que vous connaissez les nouvelles données à ce moment-là et pouvez simplement les dénormaliser dans le cadre du tx ou la mettre en file d'attente pour une dénormalisation plus tard.
wes.stueve

@RickJames est d'accord. Vous devez prendre en compte le nombre d'insertions pour ce type de stratégie et la vitesse à laquelle elles doivent être traitées.
wes.stueve
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.