Limite de alteração para “tamanho de linha Mysql muito grande”

104

Como posso mudar o limite

Tamanho da linha muito grande (> 8126). Alterar algumas colunas para TEXT ou BLOB ou usar ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSEDpode ajudar. No formato de linha atual, o BLOBprefixo de 768 bytes é armazenado em linha.

Tabela:

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
fonte
1
O que está Nosendo exibido?
hjpotter92
Não é possível atualizar o erro "Tamanho da linha muito grande (> 8126). Alterar algumas colunas para TEXT ou BLOB ou usar ROW_FORMAT = DYNAMIC ou ROW_FORMAT = COMPRESSED pode ajudar. No formato de linha atual, o prefixo BLOB de 768 bytes é armazenado em linha."
Lasha Kurt
Você pode adicionar alguns outros detalhes à sua postagem, pelo menos como um comentário?
Eineki
1
se esses dados estiverem em outra tabela, considere o uso de uma chave estrangeira, isso diminuirá drasticamente o tamanho da linha e normalizará o esquema do banco de dados.
didierc
1
@AL: Opa, você está certo - vote de perto em outro
pathikrit

Respostas:

121

A pergunta foi feita no serverfault também.

Você pode querer dar uma olhada neste artigo que explica muito sobre os tamanhos de linha do MySQL. É importante notar que mesmo se você usar os campos TEXT ou BLOB, o tamanho da linha ainda pode ser superior a 8K (limite para InnoDB) porque ele armazena os primeiros 768 bytes para cada campo embutido na página.

A maneira mais simples de corrigir isso é usar o formato de arquivo Barracuda com InnoDB. Isso basicamente elimina o problema por completo, armazenando apenas o ponteiro de 20 bytes para os dados de texto em vez de armazenar os primeiros 768 bytes.


O método que funcionou para o OP foi:

  1. Adicione o seguinte ao my.cnfarquivo na [mysqld]seção.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
    
  2. ALTERa mesa a ser usada ROW_FORMAT=COMPRESSED.

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

Existe a possibilidade de que o acima ainda não resolva seus problemas. É um bug conhecido (e verificado) com o mecanismo InnoDB , e uma correção temporária por enquanto é retornar ao mecanismo MyISAM como armazenamento temporário. Então, em seu my.cnfarquivo:

internal_tmp_disk_storage_engine=MyISAM
hjpotter92
fonte
12
+1 -> A parte innodb_file_per_table é crucial e anda de mãos dadas com a mudança do formato para Barracuda. Sem ele, o MySQL continuará silenciosamente a usar o Antelope.
Nick
1
@Eduardo Eu recomendo fazer backup dos dados primeiro. Mas sim, você também pode fazer isso na produção!
hjpotter92
3
Use innodb_file_per_table=1para ativar esta opção.
Stijn Geukens,
2
Não há garantia de que isso resolverá o problema. Veja esta postagem para um exemplo de script que adiciona essas configurações, mas ainda é capaz de reproduzir o erro.
Cerin
1
@ user1183352 Atualizei minha resposta acima. Obrigado por me lembrar novamente de mergulhar mais fundo nisso. :)
hjpotter92 01 de
61

Corri para esse problema recentemente e resolvi de uma maneira diferente. Se você estiver executando o MySQL versão 5.6.20, há um bug conhecido no sistema. Veja a documentação do MySQL

Importante Devido ao Bug # 69477, redo log escreve para grandes campos BLOB armazenados externamente podem sobrescrever o ponto de verificação mais recente. Para resolver esse bug, um patch introduzido no MySQL 5.6.20 limita o tamanho das gravações do BLOB de log de redo em 10% do tamanho do arquivo de log de redo. Como resultado desse limite, innodb_log_file_size deve ser definido com um valor maior que 10 vezes o maior tamanho de dados BLOB encontrado nas linhas de suas tabelas mais o comprimento de outros campos de comprimento variável (campos do tipo VARCHAR, VARBINARY e TEXT).

Na minha situação, a tabela de blob problemática tinha cerca de 16 MB. Assim, resolvi isso adicionando uma linha ao my.cnf que garantiu que eu tivesse pelo menos 10x esse valor e mais:

innodb_log_file_size = 256M

Colin
fonte
Spot on. Meu erro "Tamanho da linha muito grande" em um longblobcampo desapareceu assim que aumentei o innodb_log_file_sizeparâmetro. Também estava executando 5.6.20.
adamup
Obrigado. Estava executando o homebrew 5.6.21, alterar o parâmetro corrigiu o problema.
nanoman de
Esta resposta e a de @ hjpotter92 foram necessárias para corrigir esse erro para mim.
Cerin
Obrigado. Estava rodando 5.6.21 e esta solução ajudou.
petiar de
Isso também não resolveu meu problema. Estou pensando em substituir muitos dos meus campos VARCHAR por TEXTs, como vi em threads semelhantes.
PDoria 01 de
28

Defina os seguintes no seu arquivo my.cnf e reinicie o servidor mysql.

innodb_strict_mode=0
Karl
fonte
2
innodb_strict_mode=0-> sem espaços. Caso contrário, reiniciar o mariaDB 10.2 resultará em erro :-P
Pathros
Não tentei com mariadb, para MySQL não é necessário remover espaços.
Karl
1
De acordo com a documentação, desabilitar o modo estrito apenas evita que erros e avisos apareçam, por isso parece não resolver o problema! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira
2
Isso parece funcionar e me permite criar as tabelas sem problemas e armazenar dados
Chris Muench,
@ João, faz mais .. dev.mysql.com/doc/refman/8.0/en/…
Karl
24

Se você pode mudar o ENGINE e usar MyISAM em vez de InnoDB, isso deve ajudar:

ENGINE=MyISAM

Existem duas advertências com MyISAM (possivelmente mais):

  1. Você não pode usar transações.
  2. Você não pode usar restrições de chave estrangeira.
Fénix
fonte
5
Tudo bem se você não se importa em ficar sem transações e restrições de chave estrangeira. Mas esteja ciente de que você os perderá ao alternar para MyISAM.
wobbily_col
Este conselho é uma loucura - pelo menos a frase terá todas as advertências! As transações e as restrições de chave foregith são o menor dos problemas com este formato!
Hassan Syed
Desculpe, não votou nesta resposta. Atualize para mencionar todas as advertências envolvidas. Qualquer pessoa que siga este conselho muda para um formato que eu nunca usaria em nenhum sistema de produção.
Remco Wendt
2
E o MyISAM está indo embora.
Rick James
2
trabalhou para mim. Meu caso, tinha mais de 300 campos com cerca de 10 cada. Não tenho nenhum relacionamento nesta tabela, então mudar para MyISAM foi a solução.
Robert Saylor
12

Eu gostaria de compartilhar uma resposta incrível, pode ser útil. Créditos Bill Karwin, veja aqui /dba/6598/innodb-create-table-error-row-size-too-large

Eles variam de acordo com o formato de arquivo InnoDB. No momento, existem 2 formatos chamados Antelope e Barracuda.

O arquivo de espaço de tabela central (ibdata1) está sempre no formato Antelope. Se você usar arquivo por tabela, pode fazer com que os arquivos individuais usem o formato Barracuda definindo innodb_file_format = Barracuda em my.cnf.

Pontos básicos:

  1. Uma página de 16 KB de dados InnoDB deve conter pelo menos duas linhas de dados. Além disso, cada página possui um cabeçalho e um rodapé contendo somas de verificação de página, número de sequência de log e assim por diante. É aí que você obtém seu limite de um pouco menos de 8 KB por linha.

  2. Tipos de dados de tamanho fixo como INTEGER, DATE, FLOAT, CHAR são armazenados nesta página de dados primária e contam para o limite de tamanho da linha.

  3. Tipos de dados de tamanho variável, como VARCHAR, TEXT, BLOB, são armazenados em páginas de estouro, portanto, não contam totalmente para o limite de tamanho de linha. No Antelope, até 768 bytes de tais colunas são armazenados na página de dados primária, além de serem armazenados na página de estouro. O Barracuda suporta um formato de linha dinâmico, portanto, pode armazenar apenas um ponteiro de 20 bytes na página de dados primária.

  4. Os tipos de dados de tamanho variável também são prefixados com 1 ou mais bytes para codificar o comprimento. E o formato de linha InnoDB também possui uma série de deslocamentos de campo. Portanto, há uma estrutura interna mais ou menos documentada em seu wiki.

Barracuda também oferece suporte a ROW_FORMAT = COMPRESSED para obter mais eficiência de armazenamento para dados de estouro.

Também devo comentar que nunca vi uma tabela bem projetada exceder o limite de tamanho de linha. É um forte "cheiro de código" que você está violando a condição de grupos de repetição da Primeira Forma Normal.

Aman Chhabra
fonte
7

Eu tive o mesmo problema, isso resolveu para mim:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

Da documentação MYSQL :

O formato de linha DINÂMICO mantém a eficiência de armazenar toda a linha no nó de índice se ele se encaixa (como fazem os formatos COMPACT e REDUNDANT), mas este novo formato evita o problema de preencher os nós da árvore B com um grande número de bytes de dados de colunas longas. O formato DYNAMIC é baseado na ideia de que se uma parte de um valor de dados longos for armazenada fora da página, geralmente é mais eficiente armazenar todo o valor fora da página. Com o formato DYNAMIC, as colunas mais curtas provavelmente permanecerão no nó da árvore B, minimizando o número de páginas de estouro necessárias para qualquer linha.

multimediaxp
fonte
... mas você precisa ter um formato de arquivo diferente, então vc já está no Barracuda? Porque recebo um erro ao tentar esse comando, dizendoWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted
Quando deixei o HeidiSQL executar o mesmo comando por meio de sua GUI integrada, de alguma forma ele teve sucesso, mas não ajudou em nada, recebo o mesmo erro,Row size too large (>8126)
Ted
Tente definir innodb_file_format = Barracuda em my.ini e tente ALTER TABLE my_tableROW_FORMAT = DYNAMIC; novamente
multimediaxp
Sim, acho que foi o que fiz no final, na verdade, e acho que isso resolveu tudo. Mas eu também mudei muitas colunas para TEXT ao mesmo tempo em desespero =) Mas, na verdade, acho que era isso.
Ted
Bom !, se você acha que esta é uma boa resposta, dê um voto favorável e aceite como resposta válida, obrigado!
multimediaxp
5

Depois de passar horas, encontrei a solução: basta executar o seguinte SQL no administrador do MySQL para converter a tabela para MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
Iftikhar Khan
fonte
Não ajuda muito se o problema está acontecendo em uma instrução de criação de tabela.
Mark Fraser
create tabletem a mesma opção:CREATE TABLE ... ENGINE=MyISAM ...
xebeche
3

Eu tive esse problema quando estava tentando restaurar um banco de dados mysql de backup de um servidor diferente. O que resolveu esse problema para mim foi adicionar certas configurações ao my.conf (como nas perguntas acima) e, adicionalmente, alterar o arquivo de backup sql:

Etapa 1: adicione ou edite as seguintes linhas em my.conf:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Etapa 2 adicionar ROW_FORMAT = DYNAMIC à instrução de criação de tabela no arquivo de backup sql para a tabela que está causando este erro:

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;

a mudança importante acima é ROW_FORMAT = DYNAMIC; (que não foi incluído no arquivo de backup sql original)

fonte que me ajudou a resolver esse problema: MariaDB e InnoDB MySQL Tamanho da linha muito grande

matyas
fonte
1
As linhas descritas na etapa 1 não devem ter nenhum espaço. Line innodb_page_size=32Knão funcionou, pois causou um erro ao reiniciar o MariaDB 10.2 no meu caso. Em vez disso, adicionei a innodb_strict_mode=0linha, conforme descrito aqui
Pathros
1
obrigado pelo feedback Pathros, atualizei minha resposta e removi os espaços da etapa 1.
matyas
Nota para MySQL <= 5.7.5: 32K não é uma opção válida para innodb_page_size. Veja: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar
Além disso, você deve recriar todo o seu servidor mysql para scracth, pois a mudança innodb_page_sizerequer ibdata*recriação, que é uma operação destrutiva. Assista ao seu syslog para mais informações
Matija Nalis
2

As outras respostas respondem à pergunta feita. Abordarei a causa subjacente: projeto de esquema deficiente.

Não espalhe uma matriz nas colunas. Aqui você tem 3 * 10 colunas que devem ser transformadas em 10 linhas de 3 colunas em uma nova tabela (mais id, etc)

Sua Mainmesa teria apenas

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 

Sua mesa extra ( Top) teria

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

Haveria 10 (ou menos? Ou mais?) Linhas Toppara cada um id.

Isso elimina o problema original e limpa o esquema. (Isso não é "normalização", conforme debatido em alguns dos Comentários.)

Fazer não mudar para MyISAM; está indo embora.
Não se preocupe ROW_FORMAT.

Você precisará alterar seu código para fazer o JOINe para lidar com várias linhas em vez de várias colunas.

Rick James
fonte
1

Estou usando o MySQL 5.6 no AWS RDS. Eu atualizei o seguinte no grupo de parâmetros.

innodb_file_per_table=1
innodb_file_format = Barracuda

Tive que reiniciar a instância do banco de dados para que as alterações do grupo de parâmetros entrassem em vigor.

Além disso, ROW_FORMAT = COMPRESSED não era compatível. Usei o DYNAMIC como abaixo e funcionou bem.

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

O tamanho máximo da linha para uma tabela InnoDB, que se aplica a dados armazenados localmente em uma página de banco de dados, é um pouco menos do que meia página para 4 KB, 8 KB, 16 KB e 32 KB

Para páginas de 16 kb (padrão), podemos calcular:

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

Basicamente, você poderia maximizar uma linha com:

  • 11 campos varchar> 767 caracteres (latin1 = 1 byte por caractere) ou
  • 11 campos varchar> 255 caracteres (utf-8 no mysql = 3 bytes por caractere).

Lembre-se de que só irá estourar para uma página de estouro se o campo tiver> 767 bytes. Se houver muitos campos de 767 bytes, ele irá estourar (passando além de max row_size). Não é comum com latin1, mas é muito possível com utf-8 se os desenvolvedores não forem cuidadosos.

Para este caso, acho que você poderia aumentar o innodb_page_size para 32kb.

em my.cnf:

innodb_page_size=32K

Referências:

U0001
fonte
0

Eu também encontrei o mesmo problema. Eu resolvo o problema executando o seguinte sql:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Mas, eu acho que você deveria saber sobre o Row Storage .
Existem dois tipos de colunas: coluna de comprimento variável (como os tipos VARCHAR, VARBINARY e BLOB e TEXT) e coluna de comprimento fixo . Eles são armazenados em diferentes tipos de páginas.

As colunas de comprimento variável são uma exceção a esta regra. Colunas como BLOB e VARCHAR que são muito longas para caber em uma página de árvore B são armazenadas em páginas de disco alocadas separadamente chamadas de páginas de estouro. Chamamos essas colunas de colunas fora da página. Os valores dessas colunas são armazenados em listas com links simples de páginas de estouro, e cada coluna tem sua própria lista de uma ou mais páginas de estouro. Em alguns casos, todo ou um prefixo do valor da coluna longa é armazenado na árvore B, para evitar o desperdício de armazenamento e eliminar a necessidade de ler uma página separada.

e quando o objetivo de definir ROW_FORMAT é

Quando uma tabela é criada com ROW_FORMAT = DYNAMIC ou ROW_FORMAT = COMPRESSED, o InnoDB pode armazenar valores de coluna de comprimento variável longo (para os tipos VARCHAR, VARBINARY e BLOB e TEXT) totalmente fora da página, com o registro de índice agrupado contendo apenas 20- ponteiro de byte para a página de estouro.

Quer saber mais sobre os formatos de linha DINÂMICO e COMPRESSADO

Vai
fonte
0

Se isso ocorrer em um SELECT com muitas colunas, a causa pode ser que o mysql está criando uma tabela temporária. Se esta tabela for muito grande para caber na memória, ela usará seu formato de tabela temporária padrão, que é InnoDB, para armazená-la no disco. Nesse caso, os limites de tamanho do InnoDB se aplicam.

Você tem então 4 opções:

  1. mude o limite de tamanho de linha do innodb conforme indicado em outra postagem, que requer a reinicialização do servidor.
  2. mude sua consulta para incluir menos colunas ou evite causar a criação de uma tabela temporária (por exemplo, removendo as cláusulas de ordem e limite).
  3. alterando max_heap_table_size para grande, de forma que o resultado caiba na memória e não precise ser gravado no disco.
  4. mude o formato padrão da tabela temporária para MYISAM, foi isso que eu fiz. Mudança em my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

Reinicie o mysql, a consulta funciona.

bhelm
fonte
0

Aqui está uma dica simples para qualquer pessoa interessada:

Após a atualização do Debian 9 para o Debian 10 com 10.3.17-MariaDB, tenho alguns erros de bancos de dados Joomla:

[Aviso] InnoDB: Não é possível adicionar campo fieldna tabela database.tableporque depois de adicioná-lo, o tamanho da linha é 8742, que é maior do que o tamanho máximo permitido (8126) para um registro na página folha do índice.

Por precaução, eu defini innodb_default_row_format = DYNAMIC em /etc/mysql/mariadb.conf.d/50-server.cnf (era o padrão de qualquer maneira)

Então, usei o phpmyadmin para executar "Optimize table" para todas as tabelas no banco de dados Joomla. Acho que a recriação da tabela feita pelo phpmyadmin no processo ajudou. Se acontecer de você ter o phpmyadmin instalado, basta apenas alguns cliques.

joomlauser
fonte
Se você é um usuário Joomla, junte-se a nós no Joomla Stack Exchange - sempre podemos usar novos colaboradores.
mickmackusa