S'il vous plaît ne vous laissez pas berner par le message d'erreur The table 'my_table' is full
. Ce scénario rare n'a absolument rien à voir avec l'espace disque. Cette table pleine condition a à voir avec la plomberie interne d'InnoDB.
Tout d'abord, jetez un œil à ce schéma de l'architecture InnoDB
Veuillez noter que l'espace disque logique système (le fichier ibdata) n'a que 128 segments de restauration et 1023 emplacements de restauration par segment de restauration. Cela limite la taille de la capacité de restauration d'une transaction. En d'autres termes, si un segment de restauration unique a besoin de plus de 1 023 emplacements pour prendre en charge une transaction, la transaction atteindra cette table is full
condition.
Pensez au restaurant Red Lobster dans le New Jersey . Il peut avoir une capacité de 200 personnes. Si le restaurant est plein, une file de personnes peut sortir pour attendre. Si les gens sur la ligne s'impatientent, ils peuvent partir car le restaurant est plein. Évidemment, la solution ne serait pas d'agrandir le New Jersey (ou d'obtenir plus d'espace disque). La solution serait d'agrandir le restaurant Red Lobster. De cette façon, vous pouvez augmenter la capacité d'accueil à, disons, 240. Même avec cela, une ligne peut se former à l'extérieur si plus de 240 personnes décident de venir à Red Lobster.
Juste pour vous donner un exemple, j'avais un client avec 2 To d'espace disque logique système et innodb_file_per_table était désactivé. (346G pour ibdata1, la réinitialisation pour ibdata2). J'ai exécuté cette requête
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
Ensuite, j'ai soustrait InnoDBDataIndexSpace de la somme des tailles de fichier pour ibdata1 et ibdata2. J'ai deux choses qui m'ont choqué
- Il restait 106 Go à l'intérieur de l'espace disque logique du système.
- J'ai cette même
Table is Full
condition
Cela signifie que le 106 Go était utilisé pour la plomberie interne d'InnoDB. Le client utilisait ext3 à l'époque.
La solution pour moi a été d'ajouter ibdata3. J'en ai discuté dans mon ancien article Comment résoudre "La table ... est pleine" avec "innodb_file_per_table"?
J'en ai également discuté dans d'autres articles
Gardez à l'esprit que cette condition peut se produire même si innodb_file_per_table a été activé. Comment? Les annulations et les journaux d'annulation sont à l'origine de pics incontrôlés liés à la croissance d'ibdata1 .
VOTRE QUESTION RÉELLE
Étant donné que vous ajoutez un index à une table et que vous l'obtenez Table is Full
, la table doit être énorme et ne peut pas tenir dans un seul segment de restauration. Vous devez procéder comme suit:
ÉTAPE 01
Récupérez les données dans un fichier de vidage
mysqldump --no-create-info mydb mytable > table_data.sql
ÉTAPE 02
Connectez-vous à MySQL et exécutez ceci
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
ÉTAPE 03
Charger la table avec l'index supplémentaire avec les données
mysql -Dmydb < table_data.sql
C'est tout.
Vous voyez, le problème est que ALTER TABLE essaiera d'injecter toutes les lignes de votre immense table en une seule transaction. L'utilisation de mysqldump insérera les données dans la table (maintenant avec un nouvel index) des milliers de lignes à la fois, pas toutes les lignes dans une seule transaction.
Ne vous inquiétez pas what if this doesn't work?
La table d'origine sera nommée mytable_old
en cas de problème. il peut servir de sauvegarde. Vous pouvez supprimer la sauvegarde lorsque vous savez que la nouvelle table fonctionne pour vous.
Essaie !!!
MISE À JOUR 2014-06-16 11:13 EDT
Si vous êtes préoccupé par le vidage des données plus volumineuses, il suffit de le compresser.
Vous pouvez faire les mêmes étapes, mais comme suit
ÉTAPE 01
Récupérez les données dans un fichier de vidage
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
ÉTAPE 02
Connectez-vous à MySQL et exécutez ceci
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
ÉTAPE 03
Charger la table avec l'index supplémentaire avec les données
gzip -d < table_data.sql.gz | mysql -Dmydb
ou
gunzip < table_data.sql.gz | mysql -Dmydb
MISE À JOUR 2014-06-16 12:55 EDT
Je viens de penser à un autre aspect de cette question.
Puisque vous faites du DDL et non du DML, il est possible que ce ne soit pas de la plomberie interne InnoDB. Étant donné que DDL ne peut pas revenir en arrière pour InnoDB , le problème doit être la plomberie externe. Où cette plomberie externe est-elle obstruée? Je soupçonne le dossier temporaire pour le système d'exploitation. Pourquoi?
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
Voir le disk quota exceeded
? Où ce quota de disque est-il imposé?
Exécutez cette requête
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Tu as dit que c'était /var/lib/mysqltmp
Maintenant, exécutez cela dans le système d'exploitation
df -h /var/lib/mysqltmp
Quelque chose me dit que l'espace /var/lib/mysqltmp
était épuisé Après tout, vous n'avez que 14G libre. Aux yeux du DDL (pour créer l'index), un rollback s'est produit, non pas dans le fichier ibdata1, mais à l' tmpdir
emplacement. S'il /var/lib/mysqltmp
n'est monté nulle part, les données temporaires sont écrites dans la partition racine. Si /var/lib/mysqltmp
est monté quelque part, alors ce montage est rempli de données de ligne. Dans les deux cas, il n'y a pas assez de place pour terminer la DDL.
Vous avez deux options ici
OPTION 1
Vous pouvez également créer un grand disque (peut-être avec 100 + Go) et monter /var/lib/mysqltmp
sur ce grand disque.
OPTION 2
Mes suggestions en 3 étapes devraient toujours fonctionner, même avec l'espace disque limité dont vous disposez.
COMMENTAIRE
Dommage que le message d'erreur que vous avez publié indique
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Cela signifie que le système d'exploitation est très bien. Il n'existe également aucun numéro d'erreur associé à cette situation.
Il y a une autre chose que vous devez savoir. La documentation MySQL indique que la création rapide d'index pour InnoDB va toujours sur le disque :
Lors de la création de l'index, les fichiers sont écrits dans le répertoire temporaire ($ TMPDIR sous Unix,% TEMP% sous Windows ou la valeur de la variable de configuration --tmpdir). Chaque fichier temporaire est suffisamment volumineux pour contenir une colonne qui constitue le nouvel index, et chacun est supprimé dès qu'il est fusionné dans l'index final.
En raison d'une limitation de MySQL, la table est copiée, plutôt que d'utiliser «Création rapide d'index» lorsque vous créez un index sur une TABLE TEMPORAIRE. Cela a été signalé comme bogue MySQL # 39833 .
MISE À JOUR 2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Veuillez vous assurer que /mnt/cbsvolume1/var/lib/mysql
100G ou plus sont gratuits