web-dev-qa-db-fra.com

Modification de la limite pour "La taille de la ligne Mysql est trop grande"

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=COMPRESSED peut aider. Dans le format de ligne actuel, le préfixe BLOB 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 
79
Lasha Kurt

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

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

Le moyen le plus simple de résoudre ce problème consiste à utiliser le format de fichier Barracuda avec InnoDB. Cela élimine fondamentalement le problème en stocker uniquement le pointeur de 20 octets sur les données de texte au lieu de stocker les 768 premiers octets.


La méthode qui a fonctionné pour le PO il y avait:

  1. Ajoutez les éléments suivants au fichier my.cnf dans la section [mysqld].

    innodb_file_per_table=1
    innodb_file_format = Barracuda
    
  2. ALTER la 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 une solution temporaire consiste à utiliser le moteur MyISAM comme mémoire de stockage temporaire. Donc, dans votre fichier my.cnf:

internal_tmp_disk_storage_engine=MyISAM
99
hjpotter92

J'ai rencontré ce problème récemment et 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 Documentation MySQL

Important En raison du bogue n ° 69477, les écritures de journal de reprise pour les grands champs BLOB stockés en externe pourraient écraser le plus. point de contrôle récent. Pour résoudre ce problème, un correctif introduit dans MySQL 5.6.20 limite la taille de redo log BLOB écrit à 10% de la taille du fichier de journalisation. En conséquence 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 votre fichier tables plus la longueur des autres champs de longueur variable (champs de type VARCHAR, VARBINARY et TEXT).

Dans mon cas, la table blob incriminée était d'environ 16MB. Ainsi, la façon dont j'ai résolu le problème consistait à ajouter une ligne à my.cnf qui garantissait que j'avais au moins 10 fois ce montant, puis:

innodb_log_file_size = 256M

56
Colin

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.
20
phoenix

Je voudrais partager une réponse géniale, cela pourrait être utile. Crédits Bill Karwin voir ici https://dba.stackexchange.com/questions/6598/innodb-create-table-error-row-size-too-large

Ils varient selon le format de fichier InnoDB. Il existe actuellement deux 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 obliger chaque fichier à utiliser le format Barracuda en définissant innodb_file_format = Barracuda dans my.cnf.

Points de base:

  1. Une page de données InnoDB de 16 Ko doit contenir au moins deux lignes de données. De plus, chaque page comporte un en-tête et un pied de page contenant les sommes de contrôle de page, 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 primaire et sont comptabilisés 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 les pages de débordement. Par conséquent, ils ne comptent pas entièrement dans la limite de taille de ligne. Dans Antelope, jusqu’à 768 octets de telles colonnes sont stockés sur la page de données principale en plus de ceux stockés sur la page de dépassement. Barracuda prend en charge un format de ligne dynamique, de sorte qu'il ne peut stocker qu'un pointeur de 20 octets sur la page de données primaire.

  4. Les types de données de taille variable sont également préfixés avec un ou plusieurs octets pour coder la longueur. Et le format de ligne InnoDB comporte également un tableau de décalages de champs. Il existe donc une structure interne plus ou moins documentée dans leur wiki.

Barracuda prend également en charge ROW_FORMAT = COMPRESSED pour optimiser l’efficacité du stockage en cas de débordement de données.

Je dois également dire que je n’ai jamais vu une table bien conçue dépasser la limite de taille de lignes. C'est une "odeur de code" forte que vous violez la condition de groupes répétitifs de la première forme normale.

10
Aman Chhabra

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

innodb_strict_mode = 0
10
Karl

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

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

De MYSQL Documentation :

Le format de ligne DYNAMIC maintient l'efficacité du stockage de l'intégralité du fichier rangée dans le noeud d’index si cela convient (comme le font les formats COMPACT et REDUNDANT ), mais ce nouveau format évite le problème du remplissage du b-arbre. nœuds avec un grand nombre d'octets de données de longues colonnes. La dynamique Le format est basé sur l’idée que si une partie d’une valeur de données longue est stocké hors page, il est généralement plus efficace de stocker tous les fichiers valeur hors page. Avec le format DYNAMIC, les colonnes plus courtes sont susceptibles de rester dans le nœud B-tree, minimisant le nombre de pages de débordement nécessaire pour une ligne donnée.

2
multimediaxp

Après avoir passé des heures, j'ai trouvé la solution: il suffit d'exécuter le code suivant dans votre administrateur MySQL pour convertir la table en MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
1
Iftikhar Khan

J'ai aussi 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 à propos de Row Storage .
Il existe deux types de colonnes: colonne de longueur variable (type VARCHAR, VARBINARY, BLOB et TEXT) et colonne de longueur fixe. Ils sont stockés dans différents types de pages.

Les colonnes de longueur variable constituent une 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 de pages de débordement à liaison unique, chacune de ces colonnes ayant sa propre liste d'une ou de plusieurs pages de débordement. Dans certains cas, la totalité ou un préfixe de la valeur de colonne longue est stocké dans le B-tree, pour éviter de gaspiller de la mémoire et éliminer le besoin de lire une page séparée.

et lorsque le but de définir ROW_FORMAT est 

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

En savoir plus sur Formats de rangée DYNAMIC et COMPRESSED

0
Will

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

Ne pas afficher un tableau sur plusieurs colonnes. Ici vous avez 3 * 10 colonnes qui doivent être transformées en 10 lignes de 3 colonnes dans une nouvelle table (plus id, etc.)

Votre table Main aurait seulement

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 rangées (ou moins? Ou plus?) Dans Top pour chaque id.

Cela élimine votre problème d'origine et nettoie le schéma. (Ce n'est pas une "normalisation", comme cela a été débattu dans certains commentaires.)

Do not basculez sur MyISAM; ça s'en va.
Ne vous inquiétez pas pour ROW_FORMAT.

Vous devrez modifier votre code pour utiliser la variable JOIN et gérer plusieurs lignes au lieu de plusieurs colonnes.

0
Rick James

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

Vous avez alors 4 options:

  1. changez la limite de taille de ligne innodb comme indiqué dans un autre message, ce qui nécessite la réinitialisation du serveur.
  2. modifiez votre requête afin d’inclure moins de colonnes ou évitez qu’elle ne crée une table temporaire (par exemple, en supprimant les clauses order by et limit).
  3. changer max_heap_table_size doit être grand pour que le résultat tienne dans la 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.

0
bhelm

J'ai rencontré ce problème lorsque j'essayais de restaurer une base de données mysql sauvegardée à partir d'un autre serveur. Ce qui a résolu ce problème pour moi, c’est d’ajouter certains paramètres à my.conf (comme dans les questions ci-dessus) et de modifier en outre 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 à la déclaration de création de table dans le fichier de sauvegarde SQL de 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 original)

source qui m'a aidé à résoudre ce problème: MariaDB et InnoDB MySQL Taille de la ligne trop grande

0
matyas