Modifier la limite de "Taille de ligne MySQL trop grande"

104

Comment puis-je changer la limite

Taille de ligne trop grande (> 8126). Changer certaines colonnes en TEXT ou BLOB ou utiliser ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSEDpeut aider. Dans le format de ligne actuel, le BLOBpréfixe de 768 octets est stocké en ligne.

Table:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 
Lasha Kurt
la source
1
Qu'est-ce qui est Noaffiché?
hjpotter92
Impossible de mettre à jour l'erreur "Taille de ligne trop grande (> 8126). La modification de certaines colonnes en TEXT ou BLOB ou en utilisant ROW_FORMAT = DYNAMIC ou ROW_FORMAT = COMPRESSED peut aider. Dans le format de ligne actuel, le préfixe BLOB de 768 octets est stocké en ligne."
Lasha Kurt
Pouvez-vous ajouter d'autres détails à votre message, au moins en tant que commentaire?
Eineki
1
si ces données se trouvent dans une autre table, envisagez d'utiliser une clé étrangère à la place, cela réduira considérablement la taille de votre ligne et normalisera votre schéma de base de données.
didierc
1
@AL: Oups, vous avez raison - votez serré sur l'autre
pathikrit

Réponses:

121

La question a également été posée sur serverfault .

Vous voudrez peut-être jeter un œil à cet article qui explique beaucoup de choses sur la taille des lignes MySQL. Il est important de noter que même si vous utilisez des champs TEXT ou BLOB, la taille de votre ligne peut toujours être supérieure à 8K (limite pour InnoDB) car elle stocke les 768 premiers octets pour chaque champ en ligne dans la page.

Le moyen le plus simple de résoudre ce problème est d'utiliser le format de fichier Barracuda avec InnoDB. Cela élimine fondamentalement le problème en ne stockant que le pointeur de 20 octets vers les données de texte au lieu de stocker les 768 premiers octets.


La méthode qui a fonctionné pour l'OP là-bas était:

  1. Ajoutez ce qui suit au my.cnffichier sous la [mysqld]section.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
  2. ALTERla table à utiliser ROW_FORMAT=COMPRESSED.

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;

Il est possible que ce qui précède ne résout toujours pas vos problèmes. Il s'agit d'un bogue connu (et vérifié) avec le moteur InnoDB , et un correctif temporaire pour l'instant est de se replier sur le moteur MyISAM comme stockage temporaire. Donc, dans votre my.cnfdossier:

internal_tmp_disk_storage_engine=MyISAM
hjpotter92
la source
12
+1 -> La partie innodb_file_per_table est cruciale et va de pair avec le changement de format en Barracuda. Sans cela, MySQL continuera silencieusement à utiliser Antelope.
Nick
1
@Eduardo Je recommanderais d'abord de sauvegarder les données. Mais oui, vous pouvez aussi le faire en production!
hjpotter92
3
Utilisez innodb_file_per_table=1pour activer cette option.
Stijn Geukens
2
Ce n'est pas garanti pour résoudre le problème. Voir cet article pour un exemple de script qui ajoute ces paramètres mais est toujours capable de reproduire l'erreur.
Cerin
1
@ user1183352 J'ai mis à jour ma réponse ci-dessus. Merci de me rappeler à nouveau de plonger plus profondément dans ce sujet. :)
hjpotter92
61

J'ai récemment rencontré ce problème et je l'ai résolu d'une manière différente. Si vous utilisez la version 5.6.20 de MySQL, il existe un bogue connu dans le système. Voir la documentation MySQL

Important En raison du bogue n ° 69477, les écritures de journalisation pour les grands champs BLOB stockés en externe pourraient écraser le point de contrôle le plus récent. Pour résoudre ce bogue, un correctif introduit dans MySQL 5.6.20 limite la taille des écritures BLOB de journalisation à 10% de la taille du fichier de journalisation. En raison de cette limite, innodb_log_file_size doit être défini sur une valeur supérieure à 10 fois la plus grande taille de données BLOB trouvée dans les lignes de vos tables plus la longueur des autres champs de longueur variable (champs de type VARCHAR, VARBINARY et TEXT).

Dans ma situation, la table blob incriminée était d'environ 16 Mo. Ainsi, la façon dont j'ai résolu le problème était en ajoutant une ligne à my.cnf qui m'assurait d'avoir au moins 10 fois ce montant et plus encore:

innodb_log_file_size = 256M

Colin
la source
Spot sur. Mon erreur "Taille de ligne trop grande" sur un longblobchamp a disparu dès que j'ai augmenté le innodb_log_file_sizeparamètre. Courait également 5.6.20.
adamup le
Merci. Exécutait homebrew 5.6.21, la modification du paramètre a résolu le problème.
nanoman
Cela et la réponse de @ hjpotter92 étaient nécessaires pour corriger cette erreur pour moi.
Cerin
Merci. Exécutait la version 5.6.21 et cette solution a aidé.
petiar
Cela n'a pas non plus résolu mon problème. J'envisage de remplacer beaucoup de mes champs VARCHAR par des TEXT, comme je l'ai vu sur des fils similaires.
PDoria
28

Définissez les éléments suivants sur votre fichier my.cnf et redémarrez le serveur mysql.

innodb_strict_mode=0
Karl
la source
2
innodb_strict_mode=0-> pas d'espaces. Sinon, le redémarrage de mariaDB 10.2 entraîne une erreur :-P
Pathros
Je n'ai pas essayé avec mariadb, pour MySQL, il n'est pas nécessaire de supprimer les espaces.
Karl
1
Conformément à la documentation, la désactivation du mode strict empêche uniquement l'apparition d'erreurs et d'avertissements, donc cela ne semble pas résoudre le problème! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira
2
Cela semble fonctionner et permettez-moi de créer les tables sans problème et de stocker les données
Chris Muench
@ João, ça fait plus .. dev.mysql.com/doc/refman/8.0/en
Karl
23

Si vous pouvez changer de MOTEUR et utiliser MyISAM au lieu d'InnoDB, cela devrait aider:

ENGINE=MyISAM

Il y a deux mises en garde avec MyISAM (sans doute plus):

  1. Vous ne pouvez pas utiliser de transactions.
  2. Vous ne pouvez pas utiliser de contraintes de clé étrangère.
phénix
la source
6
Bien si cela ne vous dérange pas de vous passer des transactions et des contraintes de clé étrangère. Mais sachez que vous les perdez lorsque vous passez à MyISAM.
wobbily_col
1
Ce conseil est insensé - au moins phrase, il y aura toutes les mises en garde! Les transactions et les contraintes de clé sont le moindre des problèmes avec ce format!
Hassan Syed
Désolé, a voté contre cette réponse. Veuillez mettre à jour pour mentionner toutes les mises en garde impliquées. Quiconque suit simplement ces conseils passe à un format que je n'utiliserais jamais sur aucun système de production.
Remco Wendt
2
Et MyISAM s'en va.
Rick James
2
travaillé pour moi. Mon cas, j'avais plus de 300 champs d'environ 10 de longueur chacun. Je n'ai aucune relation dans ce tableau, donc passer à MyISAM était le correctif.
Robert Saylor
12

J'aimerais partager une excellente réponse, cela pourrait être utile. Crédits Bill Karwin voir ici /dba/6598/innodb-create-table-error-row-size-too-large

Ils varient selon le format de fichier InnoDB. À l'heure actuelle, il existe 2 formats appelés Antelope et Barracuda.

Le fichier de tablespace central (ibdata1) est toujours au format Antelope. Si vous utilisez fichier par table, vous pouvez faire en sorte que les fichiers individuels utilisent le format Barracuda en définissant innodb_file_format = Barracuda dans my.cnf.

Points de base:

  1. Une page de 16 Ko de données InnoDB doit contenir au moins deux lignes de données. De plus, chaque page a un en-tête et un pied de page contenant les sommes de contrôle de page et le numéro de séquence du journal, etc. C'est là que vous obtenez votre limite d'un peu moins de 8 Ko par ligne.

  2. Les types de données de taille fixe tels que INTEGER, DATE, FLOAT, CHAR sont stockés sur cette page de données principale et comptent dans la limite de taille de ligne.

  3. Les types de données de taille variable tels que VARCHAR, TEXT, BLOB sont stockés sur des pages de débordement, de sorte qu'ils ne comptent pas entièrement dans la limite de taille de ligne. Dans Antelope, jusqu'à 768 octets de ces colonnes sont stockés sur la page de données principale en plus d'être stockés sur la page de débordement. Barracuda prend en charge un format de ligne dynamique, il peut donc stocker uniquement un pointeur de 20 octets sur la page de données principale.

  4. Les types de données de taille variable sont également précédés d'un octet ou plus pour coder la longueur. Et le format de ligne InnoDB a également un tableau de décalages de champ. Il y a donc une structure interne plus ou moins documentée dans leur wiki.

Barracuda prend également en charge un ROW_FORMAT = COMPRESSED pour gagner en efficacité de stockage pour les données de débordement.

Je dois également dire que je n'ai jamais vu un tableau bien conçu dépasser la limite de taille de ligne. C'est une forte "odeur de code" que vous violez la condition de groupes répétitifs de First Normal Form.

Aman Chhabra
la source
7

J'ai eu le même problème, cela l'a résolu pour moi:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

À partir de la documentation MYSQL :

Le format de ligne DYNAMIQUE maintient l'efficacité du stockage de la ligne entière dans le nœud d'index si elle convient (comme le font les formats COMPACT et REDUNDANT), mais ce nouveau format évite le problème de remplir les nœuds d'arbre B avec un grand nombre d'octets de données de longues colonnes. Le format DYNAMIC est basé sur l'idée que si une partie d'une longue valeur de données est stockée hors page, il est généralement plus efficace de stocker toute la valeur hors page. Avec le format DYNAMIC, des colonnes plus courtes sont susceptibles de rester dans le nœud B-tree, minimisant le nombre de pages de débordement nécessaires pour une ligne donnée.

multimédiaxp
la source
... mais vous devez avoir un format de fichier différent, donc vous êtes déjà sur Barracuda? Parce que j'obtiens une erreur en essayant cette commande, en disantWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted
Quand j'ai laissé HeidiSQL exécuter la même commande via son interface graphique intégrée, cela a réussi, mais cela n'a pas du tout aidé, j'obtiens la même erreur,Row size too large (>8126)
Ted
Essayez de définir innodb_file_format = Barracuda dans my.ini et essayez ALTER TABLE my_tableROW_FORMAT = DYNAMIC; à nouveau
multimediaxp
Ouais, je pense que c'est ce que j'ai fait à la fin en fait, et je pense que cela a résolu le problème. Mais j'ai aussi changé beaucoup de colonnes en TEXT en même temps en désespoir de cause =) Thx cependant, je pense en fait que c'était tout.
Ted
Bien !, si vous pensez que c'est une bonne réponse, donnez-lui un vote et acceptez comme réponse valide, merci!
multimediaxp
5

Après avoir passé des heures, j'ai trouvé la solution: exécutez simplement le SQL suivant dans votre administrateur MySQL pour convertir la table en MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
Iftikhar Khan
la source
N'aide pas beaucoup si le problème se produit dans une instruction create table.
Mark Fraser
create tablea la même option:CREATE TABLE ... ENGINE=MyISAM ...
xebeche
3

J'ai rencontré ce problème lorsque j'essayais de restaurer une base de données mysql sauvegardée à partir d'un serveur différent. Ce qui a résolu ce problème pour moi a été d'ajouter certains paramètres à my.conf (comme dans les questions ci-dessus) et de modifier en plus le fichier de sauvegarde sql:

Étape 1: ajoutez ou modifiez les lignes suivantes dans my.conf:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Étape 2 ajoutez ROW_FORMAT = DYNAMIC à l'instruction de création de table dans le fichier de sauvegarde SQL pour la table à l'origine de cette erreur:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

le changement important ci-dessus est ROW_FORMAT = DYNAMIC; (qui n'était pas inclus dans le fichier de sauvegarde SQL d'origine)

source qui m'a aidé à résoudre ce problème: MariaDB et InnoDB MySQL Row size too large

matyas
la source
1
Les lignes décrites à l'étape 1 ne doivent pas avoir d'espace. La ligne innodb_page_size=32Kne fonctionnait pas, car elle provoquait une erreur lors du redémarrage de MariaDB 10.2 dans mon cas. Au lieu de cela, j'ai ajouté une innodb_strict_mode=0ligne, comme décrit ici
Pathros
1
merci pour les commentaires Pathros, j'ai mis à jour ma réponse et supprimé les espaces de l'étape 1.
matyas
Remarque pour MySQL <= 5.7.5: 32K n'est pas une option valide pour innodb_page_size. Voir: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar
De plus, vous devez recréer tout votre serveur mysql pour scracth, car le changement innodb_page_sizenécessite une ibdata*recréation, ce qui est une opération destructrice. Regardez votre syslog pour plus d'informations
Matija Nalis
2

Les autres réponses répondent à la question posée. Je vais aborder la cause sous-jacente: une mauvaise conception du schéma.

Ne répartissez pas un tableau sur des colonnes. Ici, vous avez 3 * 10 colonnes qui doivent être transformées en 10 lignes de 3 colonnes dans un nouveau tableau (plus id, etc.)

Votre Maintable n'aurait que

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

Votre table supplémentaire ( Top) aurait

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

Il y aurait 10 (ou moins? Ou plus?) Lignes Toppour chaqueid .

Cela élimine votre problème d'origine et nettoie le schéma. (Il ne s’agit pas de «normalisation», comme l’ont débattu certains commentaires.)

Ne passez pas à MyISAM; il s'en va.
Ne t'inquiète pas ROW_FORMAT.

Vous devrez changer votre code pour faire le JOINet pour gérer plusieurs lignes au lieu de plusieurs colonnes.

Rick James
la source
1

J'utilise MySQL 5.6 sur AWS RDS. J'ai mis à jour la suite dans le groupe de paramètres.

innodb_file_per_table=1
innodb_file_format = Barracuda

J'ai dû redémarrer l'instance de base de données pour que les changements de groupe de paramètres soient effectifs.

De plus, ROW_FORMAT = COMPRESSED n'était pas pris en charge. J'ai utilisé DYNAMIC comme ci-dessous et cela a bien fonctionné.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8
Mihir Kagrana
la source
1

La taille de ligne maximale pour une table InnoDB, qui s'applique aux données stockées localement dans une page de base de données, est légèrement inférieure à une demi-page pour 4 Ko, 8 Ko, 16 Ko et 32 ​​Ko

Pour les pages de 16 Ko (par défaut), nous pouvons calculer:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

Fondamentalement, vous pouvez maximiser une ligne avec:

  • 11 champs varchar> 767 caractères (latin1 = 1 octet par caractère) ou
  • 11 champs varchar> 255 caractères (utf-8 sur mysql = 3 octets par caractère).

N'oubliez pas qu'il ne débordera vers une page de débordement que si le champ est> 767 octets. S'il y a trop de champs de 767 octets, il sera interrompu (passant au-delà de max row_size). Pas habituel avec latin1 mais très possible avec utf-8 si les développeurs ne font pas attention.

Dans ce cas, je pense que vous pourriez éventuellement faire passer innodb_page_size à 32 ko.

dans my.cnf:

innodb_page_size=32K

Références:

U0001
la source
0

J'ai également rencontré le même problème. Je résous le problème en exécutant le sql suivant:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Mais, je pense que vous devriez savoir sur le stockage en rangée .
Il existe deux types de colonnes: une colonne de longueur variable (comme les types VARCHAR, VARBINARY et BLOB et TEXT) et une colonne de longueur fixe . Ils sont stockés dans différents types de pages.

Les colonnes de longueur variable font exception à cette règle. Les colonnes telles que BLOB et VARCHAR qui sont trop longues pour tenir sur une page B-tree sont stockées sur des pages de disque allouées séparément appelées pages de débordement. Nous appelons ces colonnes des colonnes hors page. Les valeurs de ces colonnes sont stockées dans des listes à lien unique de pages de débordement, et chacune de ces colonnes a sa propre liste d'une ou plusieurs pages de débordement. Dans certains cas, tout ou un préfixe de la valeur de la colonne longue est stocké dans l'arborescence B, pour éviter de gaspiller du stockage et de ne plus avoir à lire une page séparée.

et lorsque le but de la définition de ROW_FORMAT est

Lorsqu'une table est créée avec ROW_FORMAT = DYNAMIC ou ROW_FORMAT = COMPRESSED, InnoDB peut stocker de longues valeurs de colonne de longueur variable (pour les types VARCHAR, VARBINARY et BLOB et TEXT) entièrement hors page, avec l'enregistrement d'index clusterisé contenant seulement 20- pointeur d'octet vers la page de débordement.

Voulez en savoir plus sur les formats de lignes DYNAMIQUE et COMPRIMÉ

Volonté
la source
0

Si cela se produit sur un SELECT avec de nombreuses colonnes, la cause peut être que mysql crée une table temporaire. Si cette table est trop grande pour tenir en mémoire, elle utilisera son format de table temporaire par défaut, qui est InnoDB, pour la stocker sur le disque. Dans ce cas, les limites de taille InnoDB s'appliquent.

Vous avez alors 4 options:

  1. modifiez la limite de taille de ligne innodb comme indiqué dans un autre article, ce qui nécessite la réinitialisation du serveur.
  2. modifiez votre requête pour inclure moins de colonnes ou éviter de l'obliger à créer une table temporaire (en supprimant les clauses order by et limit).
  3. changer max_heap_table_size pour être grand afin que le résultat tienne en mémoire et n'ait pas besoin d'être écrit sur le disque.
  4. changez le format de table temporaire par défaut en MYISAM, c'est ce que j'ai fait. Changement dans my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

Redémarrez mysql, la requête fonctionne.

bhelm
la source
0

Voici un conseil simple pour toute personne intéressée:

Après la mise à niveau de Debian 9 vers Debian 10 avec 10.3.17-MariaDB, j'ai des erreurs de bases de données Joomla:

[Avertissement] InnoDB: Impossible d'ajouter un champ fielddans la table database.tablecar après l'ajout, la taille de ligne est 8742, ce qui est supérieur à la taille maximale autorisée (8126) pour un enregistrement sur la page feuille d'index.

Juste au cas où, j'ai mis innodb_default_row_format = DYNAMIC dans /etc/mysql/mariadb.conf.d/50-server.cnf (c'était quand même par défaut)

Ensuite, j'ai utilisé phpmyadmin pour exécuter "Optimiser la table" pour toutes les tables de la base de données Joomla. Je pense que la récréation de table effectuée par phpmyadmin dans le processus a aidé. Si phpmyadmin est installé, ce n'est que quelques clics à faire.

joomlauser
la source
Si vous êtes un utilisateur Joomla, rejoignez-nous sur Joomla Stack Exchange - nous pouvons toujours utiliser de nouveaux contributeurs.
mickmackusa