web-dev-qa-db-fra.com

MySQL très lent pour la requête alter table

Pourquoi faut-il plus d'une heure pour simplement mettre à jour ce tableau pour ajouter une colonne? Ce tableau comporte 15 millions de lignes. Il possède 2 index et une clé primaire à clé unique. La requête ALTER TABLE est à l'état "copie dans la table tmp" depuis 1 heure 15 minutes maintenant.

ALTER TABLE `frugg`.`item_catalog_map` 
ADD COLUMN `conversion_url` TEXT NULL DEFAULT NULL

Table:

mysql> describe item_catalog_map;
+------------------------+---------------+------+-----+---------+-------+
| Field                  | Type          | Null | Key | Default | Extra |
+------------------------+---------------+------+-----+---------+-------+
| catalog_unique_item_id | varchar(255)  | NO   | PRI | NULL    |       |
| catalog_id             | int(11)       | YES  | MUL | NULL    |       |
| item_id                | int(11)       | YES  | MUL | NULL    |       |
| price                  | decimal(10,2) | YES  |     | 0.00    |       |
+------------------------+---------------+------+-----+---------+-------+

mysql> show index from item_catalog_map;
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table            | Non_unique | Key_name             | Seq_in_index | Column_name            | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
| item_catalog_map |          0 | PRIMARY              |            1 | catalog_unique_item_id | A         |    15485115 |     NULL | NULL   |      | BTREE      |         |
| item_catalog_map |          1 | IDX_ACD6184FCC3C66FC |            1 | catalog_id             | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |
| item_catalog_map |          1 | IDX_ACD6184F126F525E |            1 | item_id                | A         |    15485115 |     NULL | NULL   | YES  | BTREE      |         |
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
48
David Parks

Les performances ALTER TABLE de MySQL peuvent devenir un problème avec les très grandes tables. MySQL effectue la plupart des modifications en créant une table vide avec la nouvelle structure souhaitée, en insérant toutes les données de l'ancienne table dans la nouvelle et en supprimant l'ancienne table. Cela peut prendre beaucoup de temps, surtout si vous manquez de mémoire et que la table est volumineuse et contient de nombreux index. De nombreuses personnes ont de l'expérience avec les opérations ALTER TABLE qui ont pris des heures ou des jours pour se terminer.

Quoi qu'il en soit, si vous devez continuer avec alter table, les ressources suivantes pourraient peut-être vous aider:

59

Si vous ne vous souciez pas des temps d'arrêt, ma suggestion utilise trois ALTER TABLE déclarations. La première instruction supprime tous les index secondaires existants. La deuxième instruction applique toutes les modifications liées aux colonnes. La dernière instruction ajoute des index secondaires supprimés et applique d'autres modifications d'index.

Deux autres conseils:

  1. Avant d'appliquer les modifications d'index, exécutez les deux instructions suivantes et remettez les valeurs à 1 après avoir terminé la modification d'index.

    SET unique_checks=0;
    SET foreign_key_checks=0;
    
  2. Lorsque vous créez plusieurs index secondaires, placez-les dans un ALTER TABLE instruction plutôt que plusieurs séparés ALTER TABLE déclarations.

L'image suivante montre la différence de performances. L'approche 1 est votre approche et l'approche 2 est ma voie. L'approche 2 prend environ 3,47% de temps par rapport à l'approche 1 pour une table de 50 m. La solution ne fonctionne que pour le moteur InnoDB MySQL (> = 5,5).

enter image description here

24
Albert Wang

Les outils Percona sont une bouée de sauvetage pour ce genre de choses avec de grandes tables.

http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html

ils ont essentiellement:

  1. créer une table en double
  2. créer un déclencheur pour synchroniser les tables
  3. données de copie en bloc
  4. vérifier
  5. tables d'échange

Cela prend une éternité, mais peu importe car cela signifie que vous pouvez modifier les colonnes sans interruption.

8
jdwyah

Votre table contient 15 millions de lignes, ce qui est quelque chose. ALTER TABLE implique la copie de toutes les données de la table et la recréation des index. Comme première mesure, essayez de copier le fichier de données (item_catalog_map.MYD si c'est MyISAM) dans votre système de fichiers et voyez combien de temps cela prend. C'est le temps que prendra ALTER TABLE au moins.

7
AndreKR

Pour minimiser le verrouillage de la grande table que je souhaite modifier, je fais ce qui suit:

  • Créez une nouvelle table vide basée sur la table existante et modifiez cette nouvelle table vide.
  • Faites un mysqldump de la grande table de sorte qu'elle ait une instruction d'insertion complète par enregistrement dans la grande table (commutateurs -c et --skip-extended-insert)
  • Importez ce mysqldump dans une base de données différente (vide) avec le large_table renommé vide.
  • Prenez un mysqldump de cette nouvelle table renommée de l'autre base de données et importez-la dans la base de données d'origine
  • Renommez large_table et large_table_new dans la base de données d'origine.

    mysql> create table DATABASE_NAME.LARGE_TABLE_NEW like DATABASE_NAME.LARGE_TABLE;
    mysql> alter table DATABASE_NAME.LARGE_TABLE_NEW add column NEW_COLUMN_NAME COL_DATA_TYPE(SIZE) default null;
    
    $ mysqldump -c --no-create-info --skip-extended-insert --no-create-db -u root -p DATABASE_NAME LARGE_TABLE > LARGE_TABLE.sql
    
    mysql> create table test.LARGE_TABLE like DATABASE_NAME.LARGE_TABLE;
    
    $ mysql -u root -p -D test < LARGE_TABLE.sql
    
    mysql> rename table test.LARGE_TABLE to test.LARGE_TABLE_NEW;
    
    $ mysqldump -c --no-create-info --skip-extended-insert --no-create-db -u root -p test LARGE_TABLE_NEW > LARGE_TABLE_NEW.sql
    
    $ mysql -u root -p -D DATABASE_NAME < LARGE_TABLE_NEW.sql
    
    mysql> rename table DATABASE_NAME.LARGE_TABLE to DATABASE_NAME.LARGE_TABLE_OLD, DATABASE_NAME.LARGE_TABLE_NEW to DATABASE_NAME.LARGE_TABLE;
    
6
gautamc