web-dev-qa-db-fra.com

ALTER TABLE sans verrouiller la table?

Lors de l'exécution d'une instruction ALTER TABLE dans MySQL, la table entière est verrouillée en lecture pour la durée de l'instruction. S'il s'agit d'une grande table, cela signifie que les instructions d'insertion ou de mise à jour peuvent être verrouillées pendant un très long moment. Existe-t-il un moyen de "modifier à chaud", comme d'ajouter une colonne de telle sorte que la table puisse toujours être mise à jour tout au long du processus?

La plupart du temps, je suis intéressé par une solution pour MySQL, mais par d’autres SGBDR si MySQL n’y parvient pas.

Pour clarifier, mon objectif est simplement d'éviter les temps d'arrêt lorsqu'une nouvelle fonctionnalité nécessitant une colonne de tableau supplémentaire est mise en production. N'importe quel schéma de base de données sera changera avec le temps, c'est juste une réalité. Je ne vois pas pourquoi nous devrions accepter que ces changements entraînent inévitablement des temps d'arrêt. c'est juste faible.

102
Daniel

La seule autre option est de faire manuellement ce que font de nombreux systèmes SGBDR ...
- Créer une nouvelle table

Vous pouvez ensuite copier le contenu de l'ancienne table sur un morceau à la fois. Bien que vous soyez toujours prudent avec tout INSERT/UPDATE/DELETE sur la table source. (Peut être géré par un déclencheur. Bien que cela provoquerait un ralentissement, ce n'est pas un verrou ...)

Une fois terminé, changez le nom de la table source, puis le nom de la nouvelle table. De préférence dans une transaction.

Une fois terminé, recompilez toutes les procédures stockées, etc. qui utilisent cette table. Les plans d'exécution ne seront probablement plus valables.

EDIT:

Certains commentaires ont été faits au sujet de cette limitation étant un peu pauvre. Alors j'ai pensé que je mettrais une nouvelle perspective dessus pour montrer pourquoi c'est comme ça ...

  • Ajouter un nouveau champ revient à changer un champ sur chaque ligne.
  • Les verrous de terrain seraient beaucoup plus difficiles que les verrous de rangée, peu importe les verrous de table.

  • En fait, vous changez la structure physique sur le disque, chaque enregistrement est déplacé.
  • C'est vraiment comme une mise à jour sur la table entière, mais avec plus d'impact ...
58
MatBailie

Percona crée un outil appelé pt-online-schema-change qui permet de le faire.

Il crée essentiellement une copie de la table et modifie la nouvelle table. Pour que la nouvelle table soit synchronisée avec l'original, elle utilise des déclencheurs pour se mettre à jour. Cela permet d'accéder à la table d'origine pendant que la nouvelle table est préparée en arrière-plan.

Ceci est similaire à la méthode suggérée par Dems ci-dessus, mais cela se fait de manière automatisée.

Certains de leurs outils ont une courbe d'apprentissage, à savoir la connexion à la base de données, mais une fois que vous en avez connaissance, ils constituent d'excellents outils.

Ex:

pt-online-schema-change --alter "ADD COLUMN c1 INT" D=db,t=numbers_are_friends
39
SeanDowney

Cette question de 2009. Maintenant, MySQL offre une solution:

DDL en ligne

Une fonctionnalité qui améliore les performances, la simultanéité et la disponibilité des tables InnoDB lors d'opérations DDL (principalement ALTER TABLE). Voir Section 14.11, "InnoDB et DDL en ligne" pour plus de détails.

Les détails varient selon le type d'opération. Dans certains cas, la table peut être modifiée simultanément lorsque ALTER TABLE est en cours. Il est possible que l’opération puisse être exécutée sans copie de table ou en utilisant un type de copie de table spécialement optimisé. L'utilisation de l'espace est contrôlée par l'option de configuration innodb_online_alter_log_max_size.

Il vous permet d’ajuster l’équilibre entre performances et concurrence lors de l’opération DDL, en choisissant de bloquer l’accès à la table (clause LOCK = EXCLUSIVE), d’autoriser les requêtes mais pas de DML (clause LOCK = SHARED), ou d’autoriser les requêtes complètes et DML. accès à la table (clause LOCK = NONE). Lorsque vous omettez la clause LOCK ou spécifiez LOCK = DEFAULT, MySQL autorise autant de simultanéité que possible en fonction du type d'opération.

Effectuer les modifications sur place autant que possible, plutôt que de créer une nouvelle copie de la table, évite les augmentations temporaires de l'utilisation de l'espace disque et de la surcharge d'E/S associées à la copie de la table et à la reconstruction des index secondaires.

voyez Manuel de référence MySQL 5.6 -> InnoDB et DDL en ligne pour plus d'informations.

Il semble que le DDL en ligne soit également disponible dans MariaDB

Vous pouvez également utiliser ALTER ONLINE TABLE pour vous assurer que votre ALTER TABLE ne bloque pas les opérations simultanées (ne prend pas de verrou). Cela équivaut à LOCK = NONE.

MariaDB KB à propos de ALTER TABLE

19
Ivanov

Voir l'outil de modification de schéma en ligne de Facebook.

http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932

Pas pour les faibles de coeur; mais ça va faire le travail.

16
Steven Soroka

Je recommande Postgres si c'est une option. Avec postgres, il n'y a pratiquement pas de temps mort avec les procédures suivantes:

Une autre caractéristique intéressante est que la plupart des instructions DDL sont transactionnelles. Vous pouvez donc effectuer une migration complète au sein d'une transaction SQL. Si un problème survient, tout est annulé.

J'ai écrit this il y a un peu de temps, peut-être que cela pourrait nous éclairer davantage sur les autres mérites.

14
mikelikespie

Puisque vous avez demandé d’autres bases de données, voici quelques informations sur Oracle.

L'ajout d'une colonne NULL à une table Oracle est une opération très rapide car elle met uniquement à jour le dictionnaire de données. Ceci maintient un verrou exclusif sur la table pendant une très courte période. Cependant, toutes les procédures stockées, les vues, les déclencheurs, etc. dépédants seront invalidés. Ceux-ci seront automatiquement recompilés.

À partir de là, vous pouvez éventuellement créer un index à l'aide de la clause ONLINE. Encore une fois, seuls les verrous de dictionnaire de données très courts. Il lit toute la table à la recherche d'index, mais ne bloque personne pour le faire.

Si vous devez ajouter une clé étrangère, vous pouvez le faire et faire en sorte qu'Oracle vous assure que les données sont correctes. Sinon, il faut lire toute la table et valider toutes les valeurs qui peuvent être lentes (créez d'abord votre index).

Si vous devez définir une valeur par défaut ou calculée dans chaque ligne de la nouvelle colonne, vous devez exécuter une mise à jour massive ou peut-être un petit programme utilitaire qui remplit les nouvelles données. Cela peut être lent, surtout si les rangées deviennent beaucoup plus grandes et ne rentrent plus dans leurs blocs. Le verrouillage peut être géré pendant ce processus. Puisque l'ancien versino de votre application, qui est toujours en cours d'exécution, ne connaît pas cette colonne, vous aurez peut-être besoin d'un déclencheur sournois ou pour spécifier un paramètre par défaut.

À partir de là, vous pouvez effectuer un basculement sur vos serveurs d’application vers la nouvelle version du code, qui continuera à fonctionner. Lâchez votre gâchette sournoise.

Vous pouvez également utiliser DBMS_REDEFINITION, une boîte noire conçue pour faire ce genre de chose.

Tout cela est tellement difficile à tester, etc. que nous avons juste une panne tôt le dimanche matin chaque fois que nous publions une version majeure.

7
WW.

Si vous ne pouvez pas vous permettre d'interrompre votre base de données lors des mises à jour d'applications, envisagez de conserver un cluster à deux nœuds pour une haute disponibilité. Avec une configuration de réplication simple, vous pouvez effectuer des modifications structurelles presque entièrement en ligne, comme celle que vous suggérez:

  • attendre que toutes les modifications soient répliquées sur un esclave passif
  • changer l'esclave passif pour qu'il soit le maître actif
  • faire les changements structurels à l'ancien maître
  • répliquer les modifications du nouveau maître vers l'ancien maître
  • faire à nouveau la permutation principale et le déploiement de la nouvelle application simultanément

Ce n'est pas toujours facile mais cela fonctionne, généralement avec 0 temps d'arrêt! Le deuxième nœud ne doit pas nécessairement être passif: il peut être utilisé pour des tests, des statistiques ou comme nœud de secours. Si vous n'avez pas d'infrastructure, la réplication peut être configurée sur une seule machine (avec deux instances de MySQL).

3
jynus

Nan. Si vous utilisez des tables MyISAM, autant que je sache, ils ne font que des verrous de table - il n'y a pas de verrous d'enregistrement, ils essaient simplement de conserver tout ce qui est hyperfast par simplicité. (Les autres tables MySQL fonctionnent différemment.) Dans tous les cas, vous pouvez copier la table dans une autre table, la modifier, puis la changer pour la mettre à jour en fonction des différences.

C’est une modification si importante que je doute que tout SGBD puisse la prendre en charge. Il est considéré comme un avantage de pouvoir le faire avec des données dans la table en premier lieu.

2
dkretz

Solution temporaire...

Une autre solution pourrait être d'ajouter une autre table avec la clé primaire de la table d'origine, ainsi que votre nouvelle colonne.

Renseignez votre clé primaire sur la nouvelle table et renseignez les valeurs de la nouvelle colonne dans votre nouvelle table, puis modifiez votre requête pour joindre cette table à des opérations sélectionnées. Vous devez également insérer, mettre à jour séparément pour cette valeur de colonne.

Lorsque vous pouvez obtenir des temps d'arrêt, vous pouvez modifier la table d'origine, modifier vos requêtes DML et supprimer votre nouvelle table créée précédemment.

Sinon, vous pouvez choisir la méthode de clustering, la réplication, l'outil pt-online-schema de percona

2
Balasundaram

En utilisant le plugin Innodb, les instructions ALTER TABLE qui ajoutent ou suppriment uniquement les index secondaires peuvent être effectuées "rapidement", c’est-à-dire sans reconstruire la table.

Cependant, d’une manière générale, dans MySQL, toute ALTER TABLE implique la reconstruction de la table entière, ce qui peut prendre un temps très long (c’est-à-dire si la table contient une quantité utile de données).

Vous devez vraiment concevoir votre application de manière à ce que les instructions ALTER TABLE ne soient pas effectuées régulièrement. vous ne voudrez certainement pas utiliser ALTER TABLE pendant l'exécution normale de l'application, sauf si vous êtes prêt à attendre ou si vous modifiez de minuscules tables.

1
MarkR

La différence entre Postgres et MySQL à cet égard réside dans le fait que Postgres ne recrée pas une table, mais modifie un dictionnaire de données similaire à Oracle. Par conséquent, l'opération est rapide, même s'il est toujours nécessaire d'attribuer un verrou de table DDL exclusif pendant très peu de temps, comme indiqué ci-dessus par d'autres.

Dans MySQL, l’opération copie les données dans une nouvelle table tout en bloquant les transactions, ce qui a été très pénible pour les administrateurs de base de données MySQL avant la v. 5.6.

La bonne nouvelle est que depuis la version 5.6 de MySQL, la restriction a été la plupart du temps levée et vous pouvez maintenant profiter de la véritable puissance de la base de données MYSQL.

1
Dmitriy Royzenberg

Vous devriez certainement essayer pt-online-schema-change. J'utilise cet outil pour effectuer des migrations sur AWS RDS avec plusieurs esclaves et cela a très bien fonctionné pour moi. J'ai écrit un article de blog détaillé sur la manière de procéder qui pourrait vous être utile.

Blog: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/

1
Rafay

Si quelqu'un lit encore ceci ou arrive, c'est le gros avantage d'utiliser un système de base de données NoSQL comme mongodb. J'ai eu le même problème avec la modification de la table afin d'ajouter des colonnes pour des fonctionnalités supplémentaires ou des index sur une grande table avec des millions de lignes et des écritures élevées. Cela finirait par se verrouiller très longtemps, ce qui frustrerait nos utilisateurs. Sur de petites tables, vous pouvez vous en tirer.

Je déteste le fait que nous devons "concevoir nos tables pour éviter de les modifier". Je ne pense pas que cela fonctionne dans le monde actuel des sites Web. Vous ne pouvez pas prédire comment les gens vont utiliser votre logiciel, c'est pourquoi vous changez rapidement les choses en fonction des commentaires des utilisateurs. Avec mongodb, vous pouvez ajouter des "colonnes" à votre guise, sans temps d'arrêt. Vous ne les ajoutez même pas vraiment, vous insérez simplement des données avec de nouvelles colonnes et le fait automatiquement.

À voir: www.mongodb.com

1
Brian Gruber

En général, la réponse sera "Non". Vous modifiez la structure de la table, ce qui nécessitera potentiellement de nombreuses mises à jour "et je suis tout à fait d'accord avec cela. Si vous vous attendez à le faire souvent, je vous proposerai une alternative aux colonnes" factices "- utilisez VIEWs au lieu de tables pour SELECTing données. IIRC, la modification de la définition d'une vue est relativement légère et l'indirection via une vue est effectuée lors de la compilation du plan de requête. Ajouter la colonne à une nouvelle table et rendre la vue JOIN dans la colonne.

Bien sûr, cela ne fonctionne que si vous pouvez utiliser des clés étrangères pour effectuer en cascade des suppressions et autres. L'autre avantage est que vous pouvez créer une nouvelle table contenant une combinaison de données et pointer la vue dessus sans perturber l'utilisation du client.

Juste une pensée.

1
D.Shawley

Je recommanderais l'une des deux approches suivantes:

  1. Concevez vos tables de base de données en tenant compte des changements potentiels. Par exemple, j'ai travaillé avec les systèmes de gestion de contenu, qui modifient régulièrement les champs de données dans le contenu. Au lieu de créer la structure de la base de données physique pour qu'elle corresponde aux exigences initiales du champ du système de gestion de contenu, il est préférable de créer une structure flexible. Dans ce cas, utilisez un champ de texte blob (varchar (max) par exemple) pour contenir des données XML flexibles. Cela rend les changements structurels très moins fréquents. Les changements structurels peuvent être coûteux, ce qui présente également un avantage.

  2. Avoir le temps de maintenance du système. Soit le système est mis hors ligne pendant les modifications (mensuelles, etc.) et les modifications sont planifiées pendant l'heure de la journée la moins traitée (de 3 à 5 heures, par exemple). Les modifications sont organisées avant le déploiement de la production. Vous disposez ainsi d'une bonne estimation du temps d'indisponibilité selon une fenêtre fixe.

2a. Avoir des serveurs redondants, de sorte que, lorsque le système est en panne, l'ensemble du site ne soit pas en panne. Cela vous permettrait de "déployer" vos mises à jour de manière échelonnée, sans supprimer l'ensemble du site.

Les options 2 et 2a peuvent ne pas être réalisables; ils ont tendance à être uniquement pour des sites/opérations plus importants. Cependant, ce sont des options valables et j’ai personnellement utilisé toutes les options présentées ici.

1
pearcewg

Comme SeanDowney l'a mentionné, pt-online-schema-change est l’un des meilleurs outils pour faire ce que vous avez décrit dans la question. J'ai récemment apporté beaucoup de modifications de schéma sur une base de données active et tout s'est très bien passé. Vous pouvez en lire plus sur mon blog ici: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/ .

1
Rafay

Les colonnes factices sont une bonne idée si vous pouvez prédire leur type (et les rendre nulles). Vérifiez comment votre moteur de stockage gère les valeurs NULL.

MyISAM verrouille tout si vous mentionnez même un nom de table en passant, au téléphone, à l'aéroport. C'est juste que ça ...

Cela étant dit, les serrures ne sont pas vraiment un gros problème; tant que vous n'essayez pas d'ajouter une valeur par défaut pour la nouvelle colonne à chaque ligne, mais que vous la laissiez comme nulle, et que votre moteur de stockage soit suffisamment intelligent pour ne pas l'écrire, vous devriez pouvoir utiliser un verrou qui n'est que assez longtemps pour mettre à jour les métadonnées. Si vous essayez d'écrire une nouvelle valeur, eh bien, vous êtes grillé.

0
SquareCog

TokuDB peut ajouter/supprimer des colonnes et ajouter des index "à chaud", la table est entièrement disponible tout au long du processus. Il est disponible via www.tokutek.com

0
tmcallaghan