MISE À JOUR: tl; dr: Le problème était que MySQL utilise le TMPDIR
lors de la création d'index. Et mon TMPDIR
était celui qui manquait d'espace disque.
Q d'origine:
J'essaie d'ajouter un index à une table InnoDB et d'obtenir un table is full error
. J'ai suffisamment d'espace disque et la configuration MySQL a un fichier par table = 1. Les données de la table sont de 85 Go et je suppose que l'index sera d'environ 20 Go à 30 Go et j'ai beaucoup plus d'espace disque que cela. J'utilise également ext3, donc je ne pense pas qu'il y ait de problème avec la limite de taille de fichier du point de vue du système d'exploitation.
L'erreur enregistrée ressemble à ceci:
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
Quelle est la cause de cela et comment puis-je résoudre ce problème?
La table de création:
`CREATE TABLE `my_table` (
`uid_from` bigint(11) NOT NULL,
`uid_to` bigint(11) NOT NULL,
`counter` int(11) NOT NULL,
`updated` date NOT NULL,
PRIMARY KEY (`uid_to`,`uid_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`
Tout comme les données sont de 87,4 Go et j'estime qu'il y a environ 1,5 milliard de lignes.
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Variable_name Value
tmpdir /tmp
[root@web ~]# df -h /tmp
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 40G 24G 14G 64% /
Veuillez ne pas vous laisser 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 nécessite plus de 1 023 emplacements pour prendre en charge une transaction, la transaction atteindra ce table is full
état.
Pensez à le 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. De toute évidence, 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é
Table is Full
étatCela 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
Mar 31, 2014
: le répertoire mysql passe à 246G après une requête, qui a échoué car la table est pleineNov 25, 2011
: ERREUR 1114 (HY000) à la ligne 6308 du fichier & La table user_analysis est pleineGardez à l'esprit que cette condition peut se produire même si innodb_file_per_table était activé. Comment? Les annulations et les journaux d'annulation sont la source de pics incontrôlés est la croissance pour ibdata1 .
Puisque vous ajoutez un index à une table et 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:
Récupérez les données dans un fichier de vidage
mysqldump --no-create-info mydb mytable > table_data.sql
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;
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 pour 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.
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
Récupérez les données dans un fichier de vidage
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
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;
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
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. Puisque 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 pour /var/lib/mysqltmp
était épuisé Après tout, vous n'avez que 14G gratuit. Aux yeux de la DDL (pour créer l'index), une restauration s'est produite, non pas dans le fichier ibdata1, mais à l'emplacement tmpdir
. Si /var/lib/mysqltmp
n'est monté nulle part, alors les données temporaires sont écrites dans la partition racine. Si /var/lib/mysqltmp
est monté quelque part, puis 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
Vous pouvez également créer un grand disque (peut-être avec 100 + Go) et monter /var/lib/mysqltmp
sur ce grand disque.
Mes suggestions en 3 étapes devraient toujours fonctionner, même avec l'espace disque limité dont vous disposez.
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 MySQL Bug # 39833 .
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Veuillez vous assurer que /mnt/cbsvolume1/var/lib/mysql
a 100G ou plus gratuit