est-il possible (et comment) de convertir une énorme table MyISAM en InnoDB sans mettre l'application hors ligne. Il nécessite d'insérer quelques lignes dans ce tableau chaque seconde, mais il est possible de le suspendre pendant environ 2 minutes.
Évidemment ALTER TABLE ... engine = innodb ne fonctionnera pas. Pour cela, j'avais le plan de créer une nouvelle table avec le moteur innodb et d'y copier le contenu. Et à la fin, suspendez le fil du journal des applications et RENAME TABLE.
Malheureusement, même la copie en petits lots de 100 lignes génère un retard important après un certain temps.
Modifier : les lignes existantes ne sont jamais modifiées, ce tableau est utilisé pour la journalisation.
Réponses:
Créez une configuration Master-Master comme suit:
logTable
logTable_new
comme innodbINSERT INTO logTable_new SELECT * FROM logTable
(psuedocode) sur MasterB, qui envoie la réplication à MasterAlogTable_new
MasterA a terminé la synchronisation, échangez les tablesla source
Compte tenu de la contrainte de:
Pendant que vous effectuez la journalisation, si vous avez un bon moyen de définir un marqueur afin que vous puissiez dire à quel moment vous démarrez le processus, vous pouvez ensuite réappliquer les journaux ou les écrire dans un fichier texte afin vous pouvez ensuite les ingérer avec
LOAD DATA INFILE
Une partie du problème est que l'écriture en lots plus petits signifie que les index doivent être recalculés encore et encore; vous feriez mieux de tout exécuter en même temps, mais cela pourrait provoquer un certain retard «notable» sur le système .. mais vous n'avez pas à le faire sur votre serveur de production.
LOAD DATA INFILE
)la source
Ajoutez-vous un délai entre chaque lot, ou mettez-vous simplement par lot les mises à jour et exécutez-vous chaque lot directement après le précédent?
Si c'est le cas, essayez d'écrire la conversion dans votre langue préférée avec quelque chose comme:
Cela devrait garantir que la conversion ne prend pas plus de la moitié de la capacité de votre serveur, même en tenant compte des différences de charge imposées car l'utilisation du système varie avec le temps.
Ou si vous souhaitez utiliser autant de temps que possible lorsque le service est relativement inactif, mais que vous devez le désactiver (en faisant potentiellement une pause pendant une période assez longue) lorsque la base de données doit effectuer un certain travail pour ses utilisateurs, remplacez
sleep for as long as the update took
parif the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>
. Cela signifie qu'il peut avancer en temps calme, mais s'arrêtera complètement lorsque le serveur est occupé à exécuter sa charge de travail normale. La détermination de la charge dépendra de votre système d'exploitation - sous Linux et similaire, la valeur moyenne de charge d'une minute/proc/loadavg
ou la sortie deuptime
devrait faire.<lower measure>
et<upper measure>
peut avoir la même valeur, bien qu'il soit habituel dans des contrôles comme celui-ci d'avoir une différence de sorte que votre processus ne continue pas à démarrer puis à s'arrêter immédiatement car son propre redémarrage a une influence sur la mesure de charge.Bien sûr, cela ne fonctionnerait pas pour les tables où les anciennes lignes peuvent être modifiées, mais fonctionnera bien pour une table de journal comme celle que vous décrivez.
Vous voudrez ignorer la sagesse habituelle de créer des index après avoir rempli la nouvelle table dans ce cas. Bien que cela soit en effet plus efficace lorsque vous voulez que les choses soient aussi rapides que possible (l'effet sur le reste du système soit damné), dans ce cas, vous ne voulez pas la grande surabondance de charge à la fin du processus comme le les index sont entièrement créés en une seule fois car il s'agit d'un processus que vous ne pouvez pas interrompre lorsque les choses sont occupées.
la source
Quelque chose comme ce travail?
$auto_increment
table de journalisationmytable
ne change pas).$auto_increment
valeur en utilisantSHOW TABLE STATUS LIKE 'mytable'
.CREATE TABLE mytable_new LIKE mytable
ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
INSERT INTO mytable SELECT * FROM mytable_old
.Vous pouvez effectuer l'étape 7 par lots ou dans une instruction, car elle ne devrait pas bloquer la journalisation normale.
la source