web-dev-qa-db-fra.com

Comment ajouter une colonne à une grande table dans MySQL

Je suis un développeur PHP alors ne soyez pas strict. J'ai une grande table ~ 5.5 Go de vidage. Notre PM a décidé de faire une nouvelle colonne dedans) pour effectuer une nouvelle fonctionnalité. La table est InnoDB donc ce que j'ai essayé:

  1. Modifier la table en écran avec verrou de table. A pris environ 30 heures et rien. Alors je l'ai juste arrêté. J'ai d'abord fait une erreur parce que je n'ai pas mis fin à toutes les transactions, mais la deuxième fois, ce n'était pas un verrouillage multiple. Le statut était copy to tmp table.

  2. Puisque j'ai également besoin d'appliquer le partitionnement pour cette table, nous décidons de faire un vidage, de renommer et de créer une table avec le même nom et une nouvelle structure. Mais le vidage fait une copie stricte (au moins je n'ai pas trouvé autre chose). J'ai donc ajouté pour vider une nouvelle colonne avec sed et l'interroger. Mais d'étranges erreurs ont commencé. Je crois que cela a été causé par charset. La table dans utf-8 et le fichier sont devenus us-ascii après sed. J'ai donc eu des erreurs (commande inconnue '\' ') sur 30% des données. C'est donc aussi une mauvaise façon.

Quelles sont les autres options pour accomplir cela et accélérer les performances (je peux le faire avec un script php, mais cela prendra des siècles). Quelle sera la performance de INSERT SELECT dans ce cas.

Merci pour toute avance.

13
ineersa

Utilisez MySQL Workbench . Vous pouvez cliquer avec le bouton droit sur une table et sélectionner "Envoyer à l'éditeur SQL" -> "Créer une instruction". De cette façon, aucune "propriété" de la table ne sera oubliée (y compris CHARSET ou COLLATE).
Avec cette énorme quantité de données, je recommanderais de nettoyer la table ou la structure de données que vous utilisez (un bon DBA est pratique). Si ce n'est pas possible:

  • renommer la table (ALTER) et en créer une nouvelle avec le script CREATE que vous obtenez à partir de Workbench. Vous pouvez également étendre cette requête avec le nouveau champ dont vous avez besoin
  • BULK LOAD les données de l'ancienne table vers la nouvelle:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;
    

    De cette façon, vous évitez l'indexation/etc pour exécuter enregistrement par enregistrement. La "mise à jour" du tableau sera encore lente (car la quantité de données est énorme) mais c'est le moyen le plus rapide auquel je peux penser.

    EDIT: Lisez l'article this pour obtenir des détails sur les commandes utilisées dans l'exemple de requête ci-dessus;)
12
user23243

alter table add column, algorithm=inplace, lock=none modifiera une table MySQL 5.6 sans copier la table et sans impact de verrouillage.

Je viens de le tester hier, une masse a inséré 70 000 lignes dans une table de partition à 280 000 lignes 7, 10 000 lignes dans chaque partition, avec 5 secondes de sommeil entre les deux pour permettre un autre débit.

A commencé les insertions en masse, puis dans une session distincte a commencé l'instruction en ligne alter ci-dessus dans MySQL Workbench, le alter s'est terminé avant les insertions, deux nouvelles colonnes ont été ajoutées et aucune ligne n'a résulté de la signification alternative MySQL n'a copié aucune ligne.

5
SAK

Votre idée sed est une méthode décente, mais sans les erreurs ou la commande que vous avez exécutée, nous ne pouvons pas vous aider.

Cependant, une méthode bien connue pour apporter des modifications en ligne à de grandes tables est pt-online-schema-change . L'oubli simpliste de ce que fait cet outil est copié à partir de la documentation:

pt-online-schema-change fonctionne en créant une copie vide de la table à modifier, en la modifiant comme vous le souhaitez, puis en copiant les lignes de la table d'origine dans la nouvelle table. Une fois la copie terminée, elle éloigne la table d'origine et la remplace par la nouvelle. Par défaut, il supprime également la table d'origine.

Cette méthode peut également prendre un certain temps, mais pendant le processus, la table d'origine sera complètement utilisable.

5
Derek Downey

Actuellement, la meilleure option pour modifier des tables énormes est probablement https://github.com/github/gh-ost

gh-ost est une solution de migration de schéma en ligne sans déclencheur pour MySQL. Il est testable et offre une pause, un contrôle/reconfiguration dynamique, un audit et de nombreux avantages opérationnels.

gh-ost génère une charge de travail légère sur le maître tout au long de la migration, découplée de la charge de travail existante sur la table migrée.

Il a été conçu sur la base d'années d'expérience avec les solutions existantes et change le paradigme des migrations de tables.

1
iJanki

Je pense que Mydumper/Myloader est un bon outil pour des opérations comme celle-ci: s'améliore chaque jour. Vous pouvez utiliser vos processeurs et charger des données en parallèle: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several- caractéristiques de performance et de convivialité /

J'ai réussi à charger des centaines de gigaoctets de tables MySQL en quelques heures.

Maintenant, quand il s'agit d'ajouter une nouvelle colonne, c'est délicat car MySQL copie la table entière dans la zone mémoire TMP avec ALTER TABLE... Bien que MySQL 5.6 dise qu'il peut effectuer des modifications de schéma en ligne, je n'ai pas encore réussi à les faire en ligne pour des tables massives sans conflit de verrouillage.

1
Kubilay