Row size Too large (> 8126)

Asked

Viewed 4,257 times

3

Gave me an error while loading mysql data.

Row size Too large (> 8126). Changing some Columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In Current Row format, BLOB prefix of 768 bytes is stored inline.

Does anyone know what kind of mistake this is?

He gave me the same mistake again. But now the solution they gave me does not work. I have several text fields, date, Longblob.

Occurs after executing this code:

$sqlupdate3 = "Update tb_detalhe_trabalhador SET
   Nome3='$Nome3',Funcao3='$Funcao3',
   MedicaValidade3='$MedicaValidade3',
   MedicaAnexo3='$MedicaAnexo3',
   EPISValidade3='$EPISValidade3',
   ProjectistaNumero3='$ProjectistaNumero3',
   ProjectistaValidade3='$ProjectistaValidade3',
   GasNumero3='$GasNumero3',
   GasValidade3='$GasValidade3',
   RedesNumero3='$RedesNumero3',
   RedesValidade3='$RedesValidade3',
   SoldadorNumero3='$SoldadorNumero3',
   SoldadorValidade3='$SoldadorValidade3',
   MecanicoNumero3='$MecanicoNumero3',
   MecanicoValidade3='$MecanicoValidade3',
   ClasSoldadorNumero3='$ClasSoldadorNumero3', 
   ClasSoldadorValidade3='$ClasSoldadorValidade3'
where id=$id ";

mysql_query($sqlupdate3) or die(mysql_error());

My table has a lot of data. Do you see this update? It has 10 more times this code. Data type text, Longblob, Date

  • Right, and now I need to have the comic book working correctly: How to fix this problem for now?

  • The most critical point, besides the context focus, is that you need to normalize the database.. See the @Zuul response and the others as well. And on the focus of your question, the Mysql error message itself already suggests fixes...

5 answers

9


The existing answers correctly address the problem, but I think when we talk about exceeding the limits of a row in the database, we’re dealing with the design of the table itself.

The error basically indicates that the amount of data is too high to fit on a line with your current configuration. Instead of changing all the configuration that will cause performance problems in the future, I suggest redesigning the table(s) to divide the information in a more efficient way.


Example

Your current structure tells me that you are storing all the data in the "tb_worker detail" table:

$sqlupdate3 = "
Update tb_detalhe_trabalhador SET
   Nome3 = '$Nome3',
   Funcao3 = '$Funcao3',
   MedicaValidade3 = '$MedicaValidade3',
   MedicaAnexo3 = '$MedicaAnexo3',
   EPISValidade3 = '$EPISValidade3',
   ProjectistaNumero3 = '$ProjectistaNumero3',
   ProjectistaValidade3 = '$ProjectistaValidade3',
   GasNumero3 = '$GasNumero3',
   GasValidade3 = '$GasValidade3',
   RedesNumero3 = '$RedesNumero3',
   RedesValidade3 = '$RedesValidade3',
   SoldadorNumero3 = '$SoldadorNumero3',
   SoldadorValidade3 = '$SoldadorValidade3',
   MecanicoNumero3 = '$MecanicoNumero3',
   MecanicoValidade3 = '$MecanicoValidade3',
   ClasSoldadorNumero3 = '$ClasSoldadorNumero3', 
   ClasSoldadorValidade3 = '$ClasSoldadorValidade3'
where id=$id ";

Data can be organized (grouped) into separate tables, thus contributing to a reduction of data per line:

Table tb_details_worker

CREATE TABLE IF NOT EXISTS `tb_detalhe_trabalhador` (
  `trabalhador_id` int(13) NOT NULL AUTO_INCREMENT COMMENT 'ID do trabalhador',
  `nome` varchar(255) NOT NULL COMMENT 'Nome do trabalhador',
  `funcao` varchar(255) NOT NULL COMMENT 'Função do trabalhador',
  PRIMARY KEY (`trabalhador_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Detalhes dos trabalhadores' AUTO_INCREMENT=1 ;

In this table are kept only the data related to the worker that are distinct, that is, they relate to each other but do not combine with other existing.

Table tb_details_worker_medica

CREATE TABLE IF NOT EXISTS `tb_detalhe_trabalhador_medica` (
  `id` int(13) NOT NULL AUTO_INCREMENT COMMENT 'Id interno',
  `trabalhador_id` int(13) NOT NULL COMMENT 'O "trabalhador_id" da tabela "tb_detalhe_trabalhador"',
  `validade` date NOT NULL DEFAULT '0000-00-00' COMMENT 'Data de validade',
  `anexo` longblob NOT NULL COMMENT 'Documento',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Detalhes do trabalhador para médica' AUTO_INCREMENT=1 ;

In this table only the data concerning the worker’s doctor are stored.

The relation between tables is created by the field trabalhador_id.

Note:
The indicated scheme is repeated for each group of data you have, that is, you would have a table for the data of Soldador , of Redes, etc....

This way you do not face problems with the line limits in your table and you get the information "tidy".


Data Insertion

Working with more than one table to store the data, you have to enter the data in another way, follow an example:

  1. Insert main table data

    $sql = "
    INSERT INTO tb_detalhe_trabalhador (nome, funcao) 
    VALUES ($Nome3, $Funcao3)";
    
    mysql_query($sql);
    
    $idTrabalhador = mysql_insert_id(); /* recolher ID que acabou de ser criado para
                                           utilizar ao inserir nas tabelas secundárias
                                           e assim criar a relação entre elas */
    
  2. Insert data into secondary tables

    $sql = "
    INSERT INTO tb_detalhe_trabalhador_medica (id, trabalhador_id, `validade`, `anexo`)
    VALUES ($idTrabalhador, $MedicaValidade3, $MedicaAnexo3)";
    
    mysql_query($sql);
    

Checks

For the insertion to be controlled, you can check the state of things as the mysql_query() is being executed:

/* Preparar Dados
 */
$sqlTrabalhador = "
INSERT INTO tb_detalhe_trabalhador (nome, funcao) 
VALUES ($Nome3, $Funcao3)";

/* Inserir
 */
if (mysql_query($sqlTrabalhador)) {

  // recolhe ID do trabalhador
  $idTrabalhador = mysql_insert_id();

  /* Preparar Dados
   */
  $sqlTrabalhadorMedica = "
  INSERT INTO tb_detalhe_trabalhador_medica (id, trabalhador_id, `validade`, `anexo`)
  VALUES ($idTrabalhador, $MedicaValidade3, $MedicaAnexo3)";

  if (mysql_query($sqlTrabalhadorMedica)) {
    // restantes inserções para as outras tabelas continuam aqui...
  }
  else {
    echo "Ocorreu um erro ao inserir os dados para Médica";
  }
}
else {
  echo "Ocorreu um erro ao inserir os detalhes do trabalhador";
}

4

The possible answers to your question are quite complex and technical because they vary by themselves file format Innodb. Nowadays there are two formats called Antelope and Barracuda.

The central tabulation file (ibdata1) is always in the format Antelope. If you use the mode file-per-table you can create individual files that can use the format Barracuda simply by setting innodb_file_format=Barracuda in the archive my.cnf:

[mysqld]
innodb_file_per_table
innodb_file_format = Barracuda

The main basic points of this occurring are:

  • A 16KB page of information stored in Innodb must contain at least two lines of information. Additionally, each page has a header and footer containing checksums, numbers of log sequences and etc. Here’s where you get your limit of a bit less than 8KB per line.

  • Data of fixed size types such as INTEGER, DATE, FLOAT and CHAR are stored on this primary data page and added to the limit size.

  • Data of variable size types, such as VARCHAR, TEXT and BLOB, are stored on the overload pages, so they do not count fully to the maximum total line limit.

In format Antelope up to 768 bytes of each column are stored on the primary data page hereafter to be stored on the overload page.

The format Barracuda supports a dynamic line format which allows it to store only a 20-byte pointer on the primary data page.

  • Data of variable size types are also prefixed by 1 or more bytes to encode their lengths. And the line format of Innodb also has an array of offsets of fields. The internal structure is more or less documented on their wiki.

The Barracuda format also supports the ROW_FORMAT=COMPRESSED to further increase the efficiency for storing overload information.

My suggestion is in the direction of you check the modeling of your database or at least of this table because it is difficult to exceed the maximum limit of the lines if the table is well modeled. This problem is a strong indication that you are violating the condition of repeat groups of the First Normal Form.

A workaround would proceed with the amendment of the my.cnf as above and change the table structure by using the ROW_FORMAT=COMPRESSED:

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

Original Response of Bill Karwin in the Stack Exchange Database Administrators.

Translation, adaptation and complement: Bruno Augusto (who will be he?)

  • A possible solution will be to divide the current table into 2 or 3 ?

  • 2

    Divide into as many as required for normalisation. Without knowing your application I could say that you would need a table for the data of workers, other for the... validity data? (I don’t know what this represents) and a third to relate both tables.

  • but creating 16 tables for each worker would help.. I can’t relate the same

  • A quick and crude explanation: The tables of workers and "validity" t~em (or would have) a primary ID, right? This third table would have at least two columns, one to relate to the primary ID of each table. When selecting the ados, you would do a JOIN.

  • 1

    +1 for the mention of the remodeling. The current implementation tends to reach a physical limitation of the platform. Remodeling and standardisation will ensure operation, stability and scalability.

  • Not to mention a much easier maintainability and, depending on the server language being used, even better performance.

Show 1 more comment

4

Reference: https://stackoverflow.com/questions/15585602/change-limit-for-mysql-row-size-too-large

Reference 2: http://docs.oracle.com/cd/E17952_01/refman-5.5-en/innodb-compression-usage.html


You might want to take a look at this artigo which explains a lot about Mysql line sizes. It is important to note that even if you use TEXT or BLOB fields, the line size may still be smaller 8K (limit for Innodb), because it stores the first 768 bytes of each field line on the page.

The simplest way to fix this is to use the formato de arquivo Barracuda with Innodb. This basically gets rid of the problem altogether, just store the 20 byte pointer to the text data instead of storing the 768 byte spruce.

1 - Adding next to my.cnf file with [mysqld] section.

innodb_file_per_table
innodb_file_format = Barracuda

2 - ALTER in the table to use ROW_FORMAT=COMPRESSED.

ALTER TABLE nome_tabela
    ENGINE=InnoDB
    ROW_FORMAT=COMPRESSED 
    KEY_BLOCK_SIZE=8;
  • There is no way to change only the 768 bytes?

  • Adding more bytes?

  • @user3253195, I know only this way. Add one more link of the documentation with a legal explanation on the subject.

  • Thanks, so in a quick way how can I change my table? Change my.cnf and 2 did not understand

  • Yes exactly as I described. Change the my.cnf and also change your table as in the second step is described.

  • and that’s all it takes?

  • my.cnf is my.ini?

  • Yes. Windows uses *.ini to boot applications, while linux uses *.cnf or *.conf, usually.

Show 3 more comments

0

In my case, what I did to solve this problem was to change the table like this:

Set oRSw = abredb.Execute("ALTER TABLE nome_tabela ENGINE=MyISAM ;")
Set oRSw = nothing
  • 2

    Can you explain why this answer helps/solves what was asked?

0

I could update change my engine from Myisam to Innodb with this approach.

SET SESSION innodb_strict_mode=0;  
ALTER TABLE `tblHostQualityVisit` ENGINE = 'InnoDB';
SET SESSION innodb_strict_mode=1;  

Browser other questions tagged

You are not signed in. Login or sign up in order to post.