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

Créer un index sur une énorme table de production MySQL sans verrouillage de table

[2017] Mise à jour :MySQL 5.6 prend en charge les mises à jour d'index en ligne

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

Dans MySQL 5.6 et supérieur, la table reste disponible pour les opérations de lecture et d'écriture pendant la création ou la suppression de l'index. L'instruction CREATE INDEX ou DROP INDEX ne se termine qu'une fois toutes les transactions accédant à la table terminées, de sorte que l'état initial de l'index reflète le contenu le plus récent de la table. Auparavant, la modification de la table pendant la création ou la suppression d'un index entraînait généralement un blocage qui annulait l'instruction INSERT, UPDATE ou DELETE sur la table.

[2015] Mise à jour des écritures de blocs d'indices de table dans MySQL 5.5

D'après la réponse ci-dessus :

"Si vous utilisez une version supérieure à 5.1, des index sont créés alors que la base de données est en ligne. Ne vous inquiétez donc pas, vous n'interromprez pas l'utilisation du système de production."

C'est ****FAUX**** (au moins pour les tables MyISAM / InnoDB, ce que 99,999 % des gens utilisent. L'édition en cluster est différente.)

Faire des opérations UPDATE sur une table va BLOQUER pendant la création de l'index. MySQL est vraiment, vraiment stupide à ce sujet (et quelques autres choses).

Scénario de test :

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Mon serveur (InnoDB) :

Server version: 5.5.25a Source distribution

Sortie (remarquez comment la 6ème opération bloque pendant les ~400 ms nécessaires pour terminer la mise à jour de l'index) :

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Vs les opérations de lecture qui ne bloquent pas (échangez le commentaire de ligne dans le script) :

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

Mettre à jour le schéma de MySQL sans temps d'arrêt

Jusqu'à présent, je ne connais qu'une seule méthode pour mettre à jour un schéma MySql et ne pas subir de panne de disponibilité. Maîtres circulaires :

  • Le maître A exécute votre base de données MySQL
  • Mettre le maître B en service et lui faire répliquer les écritures du maître A (B est un esclave de A)
  • Effectuez la mise à jour du schéma sur Master B. Il prendra du retard lors de la mise à niveau
  • Laissez Maître B rattraper son retard. Invariant :votre changement de schéma DOIT être capable de traiter des commandes répliquées à partir d'un schéma de version antérieure. Les modifications d'indexation sont éligibles. Les ajouts de colonnes simples sont généralement admissibles. Supprimer une colonne ? probablement pas.
  • Échangez ATOMIQUEMENT tous les clients du maître A vers le maître B. Si vous voulez être sûr (croyez-moi, vous le faites), vous devez vous assurer que la dernière écriture sur A est répliquée sur B AVANT B effectue sa première écriture. Si vous autorisez les écritures simultanées sur plus de 2 maîtres, ... vous comprenez mieux la réplication MySQL à un niveau PROFOND ou vous vous dirigez vers un monde de douleur. Douleur extrême. Comme, avez-vous une colonne qui est AUTOINCREMENT ??? vous êtes foutu (sauf si vous utilisez des nombres pairs sur un maître et des cotes sur l'autre). Ne faites PAS confiance à la réplication MySQL pour "faire ce qu'il faut". Ce n'est PAS intelligent et ne vous sauvera pas. C'est juste un peu moins sûr que de copier les journaux de transactions binaires à partir de la ligne de commande et de les relire à la main. Pourtant, déconnecter tous les clients de l'ancien maître et les basculer vers le nouveau maître peut être fait en quelques secondes, beaucoup plus rapidement que d'attendre une mise à niveau de schéma de plusieurs heures.
  • Maître B est maintenant votre nouveau maître. Vous avez le nouveau schéma. La vie est belle. Prenez une bière; le pire est passé.
  • Répétez le processus avec le maître A, en mettant à niveau son schéma afin qu'il devienne votre nouveau maître secondaire, prêt à prendre le relais au cas où votre maître principal (le maître B maintenant) perdrait de l'alimentation ou mourrait juste sur vous.

Un moyen facile de mettre à jour le schéma, ce n'est pas le cas. Réalisable dans un environnement de production sérieux ; oui c'est le cas. S'il vous plaît, s'il vous plaît, s'il vous plaît, s'il existe un moyen plus simple d'ajouter un index à une table MySQL sans bloquer les écritures, faites le moi savoir.

Googler m'a conduit à cet article qui décrit une technique similaire. Encore mieux, ils conseillent de boire au même moment de la procédure (Notez que j'ai écrit ma réponse avant de lire l'article) !

Changement de schéma pt-online-de Percona

L'article J'ai lié ci-dessus parle d'un outil, pt -changement-de-schéma-en-ligne , qui fonctionne comme suit :

  • Créer un nouveau tableau avec la même structure que l'original.
  • Mettre à jour le schéma sur la nouvelle table.
  • Ajouter un déclencheur sur la table d'origine afin que les modifications restent synchronisées avec la copie
  • Copier les lignes par lots à partir de la table d'origine.
  • Déplacez le tableau d'origine et remplacez-le par un nouveau tableau.
  • Supprimer l'ancienne table.

Je n'ai jamais essayé l'outil moi-même. YMMV

RDS

J'utilise actuellement MySQL via le RDS d'Amazon . C'est un service vraiment astucieux qui résume et gère MySQL, vous permettant d'ajouter de nouvelles répliques en lecture avec un seul bouton et de mettre à niveau de manière transparente la base de données sur les SKU matériels. C'est vraiment pratique. Vous n'obtenez pas un accès SUPER à la base de données, vous ne pouvez donc pas visser directement la réplication (est-ce une bénédiction ou une malédiction ?). Cependant, vous pouvez utiliser Lire la promotion des répliques pour apporter vos modifications de schéma sur un esclave en lecture seule, puis promouvez cet esclave pour qu'il devienne votre nouveau maître. Exactement la même astuce que celle que j'ai décrite ci-dessus, mais beaucoup plus facile à exécuter. Ils ne font toujours pas grand-chose pour vous aider avec la transition. Vous devez reconfigurer et redémarrer votre application.