2009-10-19 10 views
5

J'ai un programme C qui extrait une énorme source de données (20GB de texte brut) et génère des charges d'INSERT à exécuter sur une table vide simple (4 colonnes entières avec 1 clé primaire). Configuration en tant que table MEMORY, l'ensemble de la tâche se termine en 8 heures. Après la finition, environ 150 millions de lignes existent dans la table. Huit heures est un nombre complètement décent pour moi. C'est un accord unique. Le problème survient lorsque vous tentez de convertir la table MEMORY en MyISAM pour que (A) la mémoire soit libérée pour les autres processus et (B) les données ne seront pas supprimées lorsque je redémarrerai l'ordinateur.Génération d'une énorme table MySQL 150M-row

ALTER TABLE memtable ENGINE = MyISAM 

J'ai laissé cette requête exécutée ALTER TABLE pendant plus de deux jours déjà, et il ne se fait pas. Je l'ai maintenant tué.

Si je crée la table initialement en tant que MyISAM, la vitesse d'écriture semble terriblement mauvaise (en particulier du fait que la requête nécessite l'utilisation de la technique ON DUPLICATE KEY UPDATE). Je ne peux pas désactiver temporairement les touches. La table deviendrait plus de 1000 fois plus grande si je le devais et ensuite je devrais retraiter les clés et exécuter un GROUP BY sur 150 000 000 000 lignes. Umm, non.

L'une des principales contraintes à réaliser: La requête INSERT UPDATEs enregistre si la clé primaire (un hachage) existe déjà dans la table. Au tout début d'une tentative d'utilisation stricte de MyISAM, j'obtiens une vitesse approximative de 1 250 lignes par seconde. Une fois que l'indice augmente, j'imagine que ce taux sera encore plus important.


J'ai 16 Go de mémoire installée dans la machine. Quelle est la meilleure façon de générer une table massive qui finit par être une table MyISAM indexée sur disque?


Précision: Il y a beaucoup, beaucoup de UPDATEs en cours de la requête (INSERT ... ON DUPLICATE KEY UPDATE val=val+whatever). Ce n'est pas, en aucun cas, un problème de décharge brute. Mon raisonnement pour essayer une table MEMORY en premier lieu était pour accélérer toutes les recherches d'index et les changements de table qui se produisent pour chaque INSERT.

Répondre

1

Désolé de vous lancer des commentaires (le dernier, probablement).

Je viens de découvrir this article qui fournit un exemple de convertir une grande table de MyISAM à InnoDB, alors que ce n'est pas ce que vous faites, il utilise une table de mémoire intermédiaire et décrit allant de la mémoire à InnoDB de manière efficace - Commander la table en mémoire de la façon dont InnoDB s'attend à ce qu'il soit commandé à la fin. Si vous n'êtes pas lié à MyISAM, cela pourrait valoir le coup d'être vu que vous avez déjà construit une table de mémoire "correcte".

+0

InnoDB serait bien. C'est très intelligent ... J'aime ça. Merci de m'avoir fait des commentaires. Je vous en suis reconnaissant. :) – brianreavis

3

Si vous avez l'intention d'en faire une table MyISAM, pourquoi la créez-vous en mémoire en premier lieu? Si c'est seulement pour la vitesse, je pense que la conversion à une table MyISAM va annuler toute amélioration de la vitesse que vous obtenez en la créant en mémoire pour commencer. Vous dites que l'insertion directe dans une table "sur le disque" est trop lente (bien que je ne sache pas comment vous décidez quand votre méthode actuelle prend des jours), vous pouvez désactiver ou supprimer les contraintes d'unicité, puis utilisez une requête DELETE plus tard pour rétablir l'unicité, puis réactivez/ajoutez les contraintes. J'ai utilisé cette technique lors de l'importation dans une table INNODB dans le passé, et trouvé même avec la suppression plus tard, il était globalement beaucoup plus rapide. Une autre option pourrait être de créer un fichier CSV à la place des instructions INSERT, et de le charger dans la table en utilisant LOAD DATA INFILE (je crois que c'est plus rapide que les insertions, mais je ne trouve pas de référence pour le moment) ou en l'utilisant directement via le CSV storage engine, en fonction de vos besoins.

+0

J'ai mis à jour la question pour répondre à quelques-unes de vos questions. J'ai trouvé des sources qui prétendent qu'un insert CSV s'exécute plus rapidement, mais il semble assez asynchrone d'exporter des données vers un CSV de plusieurs gigaoctets ** puis de le charger dans la base de données. Cela ajoute une énorme quantité d'E/S de disque dur paresseux au problème. – brianreavis

+0

Mais vous videz dans un fichier SQL avec un ensemble d'INSERTS de toute façon n'êtes-vous pas. Je ne vois pas comment un fichier CSV est différent IO sage? J'ai ajouté un paragraphe pour expliquer une autre méthode qui pourrait corriger le problème de "l'importation dans MyISAM est trop lent". –

+0

Je ne peux pas supprimer les contraintes d'unicité. J'utilise 'ON DUPLICATE KEY UPDATE' pour mettre à jour un enregistrement si la clé primaire (un hash) existe déjà dans le capable. Si je devais supprimer la contrainte, la table serait probablement plus de 1000 fois la taille (et ce n'est pas une exagération). Il y a énormément de UPDATEs en cours - ce n'est pas seulement un vidage brut dans la base de données. – brianreavis

1

Je n'utilise pas mysql mais utilise SQL Server et c'est le processus que j'utilise pour gérer un fichier de taille similaire. D'abord, je vider le fichier dans une table de transfert qui n'a aucune contrainte. Puis j'identifie et supprime les dups de la table de transit. Ensuite, je recherche les enregistrements existants qui pourraient correspondre et mettre l'idfield dans une colonne dans la table de transfert. Puis je mets à jour où la colonne de champ d'identification n'est pas nulle et insère où elle est nulle. L'une des raisons pour lesquelles je fais tout le travail de se débarrasser des dups dans la table de mise en scène est que cela signifie moins d'impact sur la table prod quand je l'exécute et donc il est plus rapide à la fin. Tout mon processus dure moins d'une heure (et en fait beaucoup plus que ce que je décris car je dois aussi dénormaliser et nettoyer les données) et affecte les tables de production pendant moins de 15 minutes de cette période. Je n'ai pas à me soucier de l'ajustement des contraintes ou de la suppression des index ou de tout cela puisque je fais la majeure partie de mon traitement avant de toucher la table prod. Envisager si un processus simliar pourrait fonctionner mieux pour vous.

Pouvez-vous également utiliser une sorte d'importation en bloc pour obtenir les données brutes dans la table de transfert (je tire le fichier de 22 gig que j'ai dans la mise en scène en environ 16 minutes) au lieu de travailler rangée par rangée?