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 manque 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% /
Réponses:
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
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
conditionCela 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 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
ÉTAPE 02
Connectez-vous à MySQL et exécutez ceci
ÉTAPE 03
Charger la table avec l'index supplémentaire avec les données
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éemytable_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
ÉTAPE 02
Connectez-vous à MySQL et exécutez ceci
ÉTAPE 03
Charger la table avec l'index supplémentaire avec les données
ou
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?
Voir le
disk quota exceeded
? Où ce quota de disque est-il imposé?Exécutez cette requête
Tu as dit que c'était
/var/lib/mysqltmp
Maintenant, exécutez cela dans le système d'exploitation
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
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 :
MISE À JOUR 2014-06-16 13:58 EDT
Veuillez vous assurer que
/mnt/cbsvolume1/var/lib/mysql
100G ou plus sont gratuitsla source