# 1071 - A chave especificada era muito longa; o comprimento máximo da chave é 767 bytes


562

Quando eu executei o seguinte comando:

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

Recebi esta mensagem de erro:

#1071 - Specified key was too long; max key length is 767 bytes

Informações sobre a coluna1 e a coluna2:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

Eu acho que varchar(20)requer apenas 21 bytes, enquanto varchar(500)requer apenas 501 bytes. Portanto, o total de bytes é 522, menor que 767. Então, por que recebi a mensagem de erro?

#1071 - Specified key was too long; max key length is 767 bytes

5
Como não são 520 bytes, mas 2080 bytes, que excedem em muito 767 bytes, você pode executar column1 varchar (20) e column2 varchar (170). se você quer um caractere / byte equivalente, use latin1
Rahly

3
Eu acho que seu cálculo está um pouco errado aqui. O mysql usa 1 ou 2 bytes extras para registrar o comprimento dos valores: 1 byte se o comprimento máximo da coluna for 255 bytes ou menos, 2 se for maior que 255 bytes. a codificação utf8_general_ci precisa de 3 bytes por carácter tão VARCHAR (20) utiliza 61 bytes, VARCHAR (500) utiliza de 1502 bytes no total de 1563 bytes
lackovic10

3
mysql> selecione maxlen, character_set_name em information_schema.character_sets em que character_set_name in ('latin1', 'utf8', 'utf8mb4'); maxlen | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
lackovic10

15
'se você quer um caractere / byte equivalente, use latin1' Por favor , não faça isso . Latin1 realmente, realmente é uma merda. Você vai se arrepender disso.
Stijn de Witt

Consulte stackoverflow.com/a/52778785/2137210 para obter a solução
Pratik

Respostas:


490

767 bytes é a limitação de prefixo declarada para tabelas InnoDB no MySQL versão 5.6 (e versões anteriores). Tem 1.000 bytes de comprimento para tabelas MyISAM. No MySQL versão 5.7 e superior, esse limite foi aumentado para 3072 bytes.

Você também deve estar ciente de que, se você definir um índice em um grande campo char ou varchar codificado por utf8mb4, precisará dividir o comprimento máximo do prefixo do índice de 767 bytes (ou 3072 bytes) por 4, resultando em 191. Isso ocorre porque o comprimento máximo de um caractere utf8mb4 é de quatro bytes. Para um caractere utf8, seriam três bytes, resultando no comprimento máximo do prefixo do índice de 254.

Uma opção que você tem é apenas colocar um limite inferior nos seus campos VARCHAR.

Outra opção (de acordo com a resposta a esse problema ) é obter o subconjunto da coluna em vez de todo o valor, ou seja:

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

Ajuste conforme você precisa obter a chave para aplicar, mas me pergunto se valeria a pena revisar seu modelo de dados em relação a essa entidade para ver se há melhorias que permitam implementar as regras de negócios pretendidas sem atingir a limitação do MySQL.


4
Para aplicar especificando um subconjunto da coluna em vez da quantia inteira. Uma boa solução
294 Steven

204
Isso não explica por campos bem abaixo do limite de comprimento está excedendo o limite de comprimento ...
Cerin

6
Eu tentei editar as informações que o @Cerin está faltando acima, o que claramente também considerou a falta de outras pessoas, mas é rejeitado por ser mais adequado como comentário. Para aqueles que tentam entender por que 500 + 20> 767, veja o comentário de Stefan Endrullis na resposta de Julien.
Letharion

8
Isto pode ser um problema. Por exemplo: Eu tenho o nome do campo (255) e adicione exclusivo a este campo no nome (191), pois estou usando utf8mb4. Se eu tiver meu usuário, adicione seu nome com 'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs' e o outro usuário adicionará seu nome com este caractere 'IJUE3ump5fiUuJi5wK4t5a5K5a5e5e5e3e3d7e5e3e3a5e3a5e5e3a5e3a5e3d7e5e3e3e3e3e3e3d7 Deve passar na validação não bloqueada na entrada duplicada.
vee

28
O limite do índice é 767 bytes , não caracteres. E como o utf8mb4conjunto de caracteres do Mysql (que o resto do mundo chama de utf8) precisa (no máximo) de 4 bytes por caractere, você só pode indexar até VARCHAR(191). O utf8conjunto de caracteres do Mysql (que o resto do mundo chama de quebrado) precisa de no máximo 3 bytes por caractere, portanto, se você o estiver usando (o que não deveria ), você poderá indexar atéVARCHAR(255)
Stijn de Witt

404

Se alguém estiver tendo problemas com o INNODB / Utf-8 tentando colocar um UNIQUEíndice em um VARCHAR(256)campo, mude para VARCHAR(255). Parece 255 é a limitação.


247
O número de caracteres permitidos depende apenas do seu conjunto de caracteres. O UTF8 pode usar até 3 bytes por caractere, utf8mb4 até 4 bytes e latin1 apenas 1 byte. Assim, para utf8, seu tamanho de chave é limitado a 255 caracteres, desde 3*255 = 765 < 767.
Stefan Endrullis

10
Isso me salvou de muita frustração - obrigado. Deve ser a resposta aceita IMO, considerando que o usuário está usando o InnoDB alegando que atingiu uma limitação de 767b.
TheCarver 10/10

8
Como Stefan Endrullis afirmou, isso depende do conjunto de caracteres. Se você usar UTF8 que usa 3 bytes: 255x3 = 765, que é menor que o limite de 767, enquanto 256x3 = 768, que é maior. Mas se você usar UTF8mb4 sua 255 * 4 = 1020, então não é uma solução realmente
bernhardh

25
Esta resposta está correta. No entanto, se o 255 estiver realmente funcionando para você, significa que você está usando o Mysql utf8, que infelizmente está quebrado. Só pode codificar caracteres no plano multilíngue básico. Você terá problemas com os personagens que ficam fora disso. Por exemplo, os caracteres Emoji que eles adicionaram caem fora dele, eu acho. Então, em vez de mudar para VARCHAR(255), mude para VARCHAR(191) e mude a codificação para utf8mb4(que na verdade é apenas utf8, mas o MySql queria impedir. Compat).
Stijn de Witt

1
Não é útil para minha restrição única de várias colunas. Também não funcionaria para a restrição única de várias colunas do OP. (daria um tamanho total de 825 bytes)
Barett

351

Quando você atinge o limite. Defina o seguinte.

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)

34
Esta é a melhor resposta. Simples, direto ao ponto e também inclui utf8mb4limit (que é a codificação mais usada para bancos de dados mais recentes, pois aceita emojis / etc).
Claudio Holanda

10
porque 767/4 ~ = 191 e 767/3 ~ = 255
contador 8/17/17

11
onde e como configurá-lo?
Dinesh Sunny

1
Sim, especificando ENGINE=InnoDB DEFAULT CHARSET=utf8no final da CREATE TABLEdeclaração que eu consegui ter uma VARCHAR(255)chave primária. Obrigado.
xonya

1
alguém dar-lhe um exceder o limite de 191 :)
cagcak

147

O MySQL assume o pior caso para o número de bytes por caractere na string. Para a codificação 'utf8' do MySQL, são 3 bytes por caractere, uma vez que essa codificação não permite caracteres além U+FFFF. Para a codificação 'utf8mb4' do MySQL, são 4 bytes por caractere, já que é o que o MySQL chama de UTF-8 real.

Então, supondo que você esteja usando 'utf8', sua primeira coluna receberá 60 bytes do índice e a segunda, 1500.


4
- O que presumivelmente significa que, ao usar utf8mb4, eu preciso configurá-los para (no máximo) 191 como 191 * 4 = 764 <767
Isaac

2
@Isaac Sim, exatamente,
morganwahl

2
Eu acho que essa pode ser a resposta certa, mas você poderia elaborar o que seria necessário fazer para corrigir esse problema? Pelo menos para noobs do MySQL como eu?
Adam Grant

Não há uma maneira de contornar esse limite de índice. A questão aqui é sobre restrições únicas; para eles, é possível ter uma coluna de texto de tamanho ilimitado e outra onde você armazena um hash (como MD5) desse texto e usa a coluna de hash para sua restrição exclusiva. Você precisará garantir que seu programa mantenha os hashes atualizados quando ele altera o texto, mas há várias maneiras de lidar com isso sem muita dificuldade. Francamente, o MySQL deve implementar uma coisa dessas para que você não precise; Eu não ficaria surpreso se o MariaDB tivesse algo assim embutido.
morganwahl

Um índice exclusivo em uma coluna varchar muito longa é raro. Pense por que você precisa, porque pode ser um problema de design. Se você deseja apenas um índice para pesquisa, considere um campo de 'palavras-chave' que se ajuste a 191 caracteres ou divida o texto em uma descrição curta e em texto longo / completo etc. como Apache Lucene.
Stijn de Witt

56

execute esta consulta antes da sua consulta:

SET @@global.innodb_large_prefix = 1;

isso aumentará o limite para 3072 bytes.


4
Existe alguma desvantagem em mudar para innodb_large_prefix globalmente? E esse DB é "global" ou todos os DB TOTALMENTE GLOBAL?
SciPhi

5
Aplica-se apenas ao usar formatos de linha não padrão. Consulte dev.mysql.com/doc/refman/5.5/en/… . Especificamente, 'Ative esta opção para permitir prefixos de chave de índice com mais de 767 bytes (até 3072 bytes), para tabelas InnoDB que usam os formatos de linha DYNAMIC e COMPRESSED.' O formato da linha padrão não é afetado.
Chris Lear

5
Isso funcionou bem para mim - mais detalhes e um guia podem ser encontrados aqui: mechanics.flite.com/blog/2014/07/29/…
cwd

1
precisamos reiniciar o servidor mysql depois disso?
precisa saber é o seguinte

7
Detalhes ausentes importantes desta resposta. innodb_file_formatdeve estar BARRACUDAe No nível da mesa, você deve usar ROW_FORMAT=DYNAMICou ROW_FORMAT=COMPRESSED. Veja o comentário do @ cwd acima com o guia.
Q0rban

46

Solução para o Laravel Framework

Conforme a documentação do Laravel 5.4. * ; Você deve definir o comprimento padrão da string dentro do bootmétodo do app/Providers/AppServiceProvider.phparquivo da seguinte maneira:

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

Explicação dessa correção, fornecida pela documentação do Laravel 5.4. * :

O Laravel usa o utf8mb4conjunto de caracteres por padrão, que inclui suporte para armazenar "emojis" no banco de dados. Se você estiver executando uma versão do MySQL mais antiga que a versão 5.7.7 ou MariaDB mais antiga que a versão 10.2.2, pode ser necessário configurar manualmente o comprimento padrão da sequência gerada pelas migrações para que o MySQL crie índices para elas. Você pode configurar isso chamando o Schema::defaultStringLengthmétodo dentro do seu AppServiceProvider.

Como alternativa, você pode ativar a innodb_large_prefixopção para o seu banco de dados. Consulte a documentação do seu banco de dados para obter instruções sobre como ativar corretamente esta opção.


10
@BojanPetkovic bem, acabei de sair de um problema no Laravel, e essa resposta realmente resolveu meu problema.
mkmnstr

Esta resposta é ótima. Mas alguém sabe, por que exatamente isso funciona?
UeliDeSchwert 10/04

1
@Bobby Laravel documentação dá a sua explicação na rubrica "Índice Lengths & MySQL / MariaDB" laravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat

1
@Bobby Atualizei a resposta. Eu adicionei a explicação dada pela documentação do laravel para essa correção.
Ali Shaukat

39

Qual codificação de caracteres você está usando? Alguns conjuntos de caracteres (como UTF-16 etc.) usam mais de um byte por caractere.


8
Se é UTF8, um personagem pode usar até 4 bytes, de modo que 20 coluna de caracteres é 20 * 4 + 1bytes, ea coluna de char 500 é 500 * 4 + 2bytes
Thanatos

5
Pelo que vale, acabei de ter o mesmo problema e a mudança de utf8_general_ci para utf8_unicode_ci resolveu o problema para mim. Mas não sei por que :(
Andresch Serj 17/07/2012

11
Para uma VARCHAR(256)coluna com um UNIQUEíndice, alterar a intercalação não teve efeito para mim, como ocorreu para @Andresch. No entanto, reduzir o comprimento de 256 para 255 resolveu o problema. Não entendo por que, como 767 / max 4 bytes por caractere renderiam no máximo 191?
Arjan

10
255*3 = 765; 256*3 = 768. Parece que o seu servidor foi asssuming 3 bytes por personagem, @ Arjan
Âmbar

21
@ Greg: Você está correto, mas isso deve ser elaborado: o próprio UTF-8 usa 1 a 4 bytes por ponto de código. Os "conjuntos de caracteres" do MySQL (realmente codificações) têm um conjunto de caracteres chamado "utf8" que é capaz de codificar parte do UTF-8 e usa 1 a 3 bytes por ponto de código, e é incapaz de codificar pontos de código fora do BMP. Ele também inclui outro conjunto de caracteres chamado "utf8mb4", que usa de 1 a 4 bytes por ponto de código e é capaz de codificar todos os pontos de código Unicode. (utf8mb4 é UTF-8, UTF-8 é uma versão estranha de UTF-8.)
Thanatos

28

Acho varchar (20) requer apenas 21 bytes enquanto varchar (500) requer apenas 501 bytes. Portanto, o total de bytes é 522, menor que 767. Então, por que recebi a mensagem de erro?

O UTF8 requer 3 bytes por caractere para armazenar a sequência, portanto, no seu caso, 20 + 500 caracteres = 20 * 3 + 500 * 3 = 1560 bytes, que são mais do que permitidos 767 bytes.

O limite para UTF8 é 767/3 = 255 caracteres , para UTF8mb4, que usa 4 bytes por caractere, é 767/4 = 191 caracteres.


Existem duas soluções para esse problema se você precisar usar uma coluna mais longa que o limite:

  1. Use codificação "mais barata" (aquela que requer menos bytes por caractere).
    No meu caso, eu precisei adicionar um índice Exclusivo na coluna que contém a sequência de caracteres de artigo SEO, como eu uso apenas [A-z0-9\-]caracteres para SEO, usei latin1_general_cique usa apenas um byte por caractere e assim a coluna pode ter 767 bytes de comprimento.
  2. Crie um hash a partir da sua coluna e use apenas um índice exclusivo.
    A outra opção para mim era criar outra coluna que armazenasse o hash do SEO. Essa coluna teria a UNIQUEchave para garantir que os valores do SEO sejam únicos. Eu também adicionaria um KEYíndice à coluna SEO original para acelerar a pesquisa.

Isso fez o truque. Eu tive varchar (256) e tive que alterá-lo para varchar (250).
MARMAR

25

A resposta sobre por que você recebe a mensagem de erro já foi respondida por muitos usuários aqui. Minha resposta é sobre como consertar e usá-lo como está.

Consulte a partir deste link .

  1. Abra o cliente MySQL (ou cliente MariaDB). É uma ferramenta de linha de comando.
  2. Ele pedirá sua senha, digite sua senha correta.
  3. Selecione seu banco de dados usando este comando use my_database_name;

Banco de dados alterado

  1. set global innodb_large_prefix=on;

Consulta OK, 0 linhas afetadas (0,00 s)

  1. set global innodb_file_format=Barracuda;

Consulta OK, 0 linhas afetadas (0,02 s)

  1. Vá para o seu banco de dados no phpMyAdmin ou algo parecido para facilitar o gerenciamento. > Selecione banco de dados> Visualizar estrutura da tabela > Vá para a guia Operações . > Altere ROW_FORMAT para DYNAMIC e salve as alterações.
  2. Vá para a guia estrutura da tabela > clique no botão Exclusivo .
  3. Feito. Agora não deve ter erros.

O problema dessa correção é se você exportar db para outro servidor (por exemplo, de host local para host real) e não puder usar a linha de comando do MySQL nesse servidor. Você não pode fazê-lo funcionar lá.


se você ainda estiver com erro após inserir a consulta acima, tente ir para "phpmyadmin"> defina o "agrupamento" como sua preferência (para mim eu uso "utf8_general_ci")> clique em Aplicar (mesmo que já seja utf8)
Anthony Kal

Não estou usando uma ferramenta que funcione com suas instruções, mas ainda estou votando por tentar ajudar as pessoas a resolver o problema. Existem infinitas explicações sobre o que causa o problema, mas notavelmente pouco sobre como realmente resolvê-lo.
Teekin 19/06/19

20
Specified key was too long; max key length is 767 bytes

Você recebeu essa mensagem porque 1 byte é igual a 1 caractere apenas se você usar o latin-1conjunto de caracteres. Se você usar utf8, cada caractere será considerado 3 bytes ao definir sua coluna-chave. Se você usar utf8mb4, cada caractere será considerado com 4 bytes ao definir sua coluna-chave. Portanto, você precisa multiplicar o limite de caracteres do campo-chave por 1, 3 ou 4 (no meu exemplo) para determinar o número de bytes que o campo-chave está tentando permitir. Se você estiver usando uft8mb4, poderá definir apenas 191 caracteres para um campo de chave primária nativo InnoDB. Apenas não viole 767 bytes.


17

Substitua utf8mb4por utf8no seu arquivo de importação.

insira a descrição da imagem aqui


Por que exatamente alguém deveria fazer isso? Além disso, se houver alguma desvantagem (que eu assumo), você deve mencionar isso
Nico Haase

16

você pode adicionar uma coluna do md5 de colunas longas


Observe que isso não permitirá que você faça varreduras de intervalo nessas colunas. Os comprimentos de prefixo nos VARCHARs permitirão manter essa característica, causando, possivelmente, correspondências falsas no índice (e varredura e pesquisa de linha para eliminá-las) (consulte a resposta aceita). (Este é essencialmente um índice hash implementado manualmente, o que, infelizmente, o MySQL não suporta com tabelas InnoDB.)
Thanatos

Não pude usar índices de prefixo porque precisava manter a compatibilidade com o H2 para fins de teste e descobri que usar uma coluna hash funciona bem. Eu recomendaria fortemente o uso de uma função resistente a colisões, como SHA1, em vez de MD5, para impedir que usuários mal-intencionados criem colisões. Uma colisão de índice pode ser explorada para vazar dados se uma de suas consultas apenas verificar o valor do hash, e não o valor completo da coluna.
Little Mike

13

Encontramos esse problema ao tentar adicionar um índice UNIQUE a um campo VARCHAR (255) usando utf8mb4. Embora o problema já esteja bem delineado aqui, eu gostaria de acrescentar alguns conselhos práticos sobre como descobrimos e resolvemos isso.

Ao usar utf8mb4, os caracteres contam como 4 bytes, enquanto em utf8, eles podem ter 3 bytes. Os bancos de dados do InnoDB têm um limite que os índices podem conter apenas 767 bytes. Portanto, ao usar utf8, você pode armazenar 255 caracteres (767/3 = 255), mas usando utf8mb4, você pode armazenar apenas 191 caracteres (767/4 = 191).

Você é absolutamente capaz de adicionar índices regulares para VARCHAR(255)campos usando utf8mb4, mas o que acontece é que o tamanho do índice é truncado automaticamente em 191 caracteres - como unique_keyaqui:

Captura de tela do Sequel Pro mostrando o índice truncado em 191 caracteres

Isso é bom, porque índices regulares são usados ​​apenas para ajudar o MySQL a pesquisar seus dados mais rapidamente. O campo inteiro não precisa ser indexado.

Então, por que o MySQL trunca o índice automaticamente para índices regulares, mas gera um erro explícito ao tentar fazer isso para índices exclusivos? Bem, para que o MySQL possa descobrir se o valor que está sendo inserido ou atualizado já existe, ele precisa indexar todo o valor e não apenas parte dele.

No final do dia, se você deseja ter um índice exclusivo em um campo, todo o conteúdo do campo deve caber no índice. Para utf8mb4, isso significa reduzir o comprimento do campo VARCHAR para 191 caracteres ou menos. Se você não precisar de utf8mb4 para essa tabela ou campo, poderá devolvê-lo ao utf8 e poder manter seus 255 campos de comprimento.


11

Aqui está a minha resposta original:

Acabei de largar o banco de dados e recriar assim, e o erro se foi:

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

No entanto, não funciona para todos os casos.

Na verdade, é um problema usar índices nas colunas VARCHAR com o conjunto de caracteres utf8(ou utf8mb4), com colunas VARCHAR que possuem mais de um determinado comprimento de caracteres. No caso de utf8mb4, esse determinado comprimento é 191.

Consulte a seção Índice longo neste artigo para obter mais informações sobre como usar índices longos no banco de dados MySQL: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- conjunto de caracteres para utf8mb4


Resolvido o problema para a instalação do openmeetings (BTW você salvou a minha noite :-)
Ludo

11

5 soluções alternativas:

O limite foi aumentado em 5.7.7 (MariaDB 10.2.2?). E pode ser aumentado com algum trabalho em 5.6 (10.1).

Se você estiver atingindo o limite por tentar usar o CHARACTER SET utf8mb4. Em seguida, siga um destes procedimentos (cada um tem uma desvantagem) para evitar o erro:

  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
  Use a "prefix" index -- you lose some of the performance benefits.
  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes


10

Corrigi esse problema com:

varchar(200) 

substituído por

varchar(191)

todo o varchar que tem mais de 200 substitui-os por 191 ou os define como texto.


Isso é o que funcionou para mim também. Eu tinha um varchar (250), mas os dados nunca foram tão longos. Alterado para varchar (100). Obrigado pela ideia :)
Arun Basil Lal

7

Eu fiz alguma pesquisa sobre este tópico, finalmente recebi algumas alterações personalizadas

Para o MySQL workbench 6.3.7 Versão está disponível uma fase gráfica

  1. Inicie o Workbench e selecione a conexão.
  2. Vá para gerenciamento ou Instância e selecione Arquivo de opções.
  3. Se o Workbench solicitar permissão para ler o arquivo de configuração e permitir, pressione OK duas vezes.
  4. No centro, aparece a janela do arquivo de opções do administrador.
  5. Vá para a guia InnoDB e verifique o innodb_large_prefix, se não estiver marcado na seção Geral.
  6. defina o valor da opção innodb_default_row_format como DYNAMIC.

Para as versões abaixo da 6.3.7, as opções diretas não estão disponíveis, portanto, é necessário ir com o prompt de comando

  1. Inicie o CMD como administrador.
  2. Ir para o diretório em que o servidor mysql está instalado A maioria dos casos está em "C: \ Arquivos de Programas \ MySQL \ MySQL Server 5.7 \ bin", então o comando é "cd \" "cd Arquivos de Programas \ MySQL \ MySQL Server 5.7 \ bin".
  3. Agora execute o comando mysql -u userName -p databasescheema Agora ele pediu a senha do respectivo usuário. Forneça a senha e entre no prompt do mysql.
  4. Temos que definir algumas configurações globais, digite os comandos abaixo, um por um, definir global innodb_large_prefix = on; definir global innodb_file_format = barracuda; definir global innodb_file_per_table = true;
  5. Agora, finalmente, temos que alterar o ROW_FORMAT da tabela necessária, por padrão, seu COMPACT, temos que configurá-lo para DYNAMIC.
  6. use o seguinte comando alter table table_name ROW_FORMAT = DYNAMIC;
  7. Feito

Não foi possível encontrar o seguinte: 6. defina o valor da opção innodb_default_row_format como DYNAMIC.
Adrian Cid Almaguer

se eu usar set global innodb_default_row_format = DYNAMIC;, vejo esta mensagem: ERRO 1193 (HY000): Variável de sistema desconhecida 'innodb_default_row_format'
Adrian Cid Almaguer

como você obteve erro do ambiente de trabalho para o cmd? Eu fiz isso da bancada de trabalho, tem opção diretamente.
Abhishek

Eu faço isso a partir do CMD porque não vejo a opção no Workbench
Adrian Cid Almaguer

1
Eu vejo o problema que esta var foi introduzida na v5.7.9 e eu tenho a versão v5.6.33, obrigado #
Adrian Cid Almaguer

7

Para laravel 5.7 a 6.0

Passos a seguir

  1. Vá para App\Providers\AppServiceProvider.php.
  2. Adicione isso ao provedor use Illuminate\Support\Facades\Schema;no topo.
  3. Dentro da função de inicialização Schema::defaultStringLength(191);

isso tudo, aproveite.


Também trabalhou para o Laravel 5.8.
Neo

Esta é uma solução ruim. Razão: os índices não devem ser infinitamente longos. Quando você aplica um índice exclusivo a algo, deseja que o índice seja corrigido com a maior parte do tempo. Isso significa que você NÃO DEVE criar coisas como emailúnicas, mas deve enviar um e-mail com hash e torná-lo único. Diferentemente dos dados brutos de string, os hashes têm largura fixa e podem ser indexados e tornar únicos sem problemas. Em vez de entender o problema, você está espalhando práticas terríveis que não são dimensionáveis.
NB

5

mude seu agrupamento. Você pode usar utf8_general_ci que suporta quase todos


"Quase" é uma boa dica de que essa não é uma solução a longo prazo
Nico Haase

4

Apenas mudar utf8mb4para a utf8criação de tabelas resolveu meu problema. Por exemplo: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;para CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.


4

Para consertar isso, isso funciona para mim como um encanto.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Confirmo que meu problema também foi o agrupamento do banco de dados. Eu não tenho nenhuma explicação para isso. Eu uso o mysql v5.6.32 e o agrupamento do banco de dados foi utf8mb4_unicode_ci.
mahyard

2

Com base na coluna fornecida abaixo, essas duas colunas de sequência variável estão usando utf8_general_ciagrupamento ( utf8charset está implícito).

No MySQL, utf8charset usa no máximo 3 bytes para cada caractere. Portanto, seria necessário alocar 500 * 3 = 1500 bytes, o que é muito maior do que os 767 bytes permitidos pelo MySQL. É por isso que você está recebendo esse erro 1071.

Em outras palavras, você precisa calcular a contagem de caracteres com base na representação de bytes do conjunto de caracteres, pois nem todo conjunto de caracteres é uma representação de byte único (como você presumiu.) O IE utf8no MySQL usa no máximo 3 bytes por caractere, 767 / 3≈255 caracteres e, para utf8mb4, no máximo, uma representação de 4 bytes, 767/4 × 191 caracteres.

Também é sabido que o MySQL

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

1

Achei esta consulta útil para detectar quais colunas tinham um índice que viola o comprimento máximo:

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

1

Por favor, verifique se sql_modeé como

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

se for, mude para

sql_mode=NO_ENGINE_SUBSTITUTION

OU

reinicie o servidor alterando o arquivo my.cnf (colocando a seguir)

innodb_large_prefix=on

1

No meu caso, tive esse problema ao fazer backup de um banco de dados usando os caracteres de saída / entrada de redirecionamento do linux. Portanto, altero a sintaxe conforme descrito abaixo. PS: usando um terminal linux ou mac.

Backup (sem o> redirecionamento)

# mysqldump -u root -p databasename -r bkp.sql

Restaurar (sem o <redirecionamento)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

O erro "Chave especificada era muito longa; o comprimento máximo da chave é 767 bytes" simples desapareceu.


1

Comprimentos de índice e MySQL / MariaDB


O Laravel usa o conjunto de caracteres utf8mb4 por padrão, que inclui suporte para armazenar "emojis" no banco de dados. Se você estiver executando uma versão do MySQL mais antiga que a versão 5.7.7 ou MariaDB mais antiga que a versão 10.2.2, pode ser necessário configurar manualmente o comprimento padrão da sequência gerada pelas migrações para que o MySQL crie índices para elas. Você pode configurar isso chamando o método Schema :: defaultStringLength em seu AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

Como alternativa, você pode ativar a opção innodb_large_prefix para o seu banco de dados. Consulte a documentação do seu banco de dados para obter instruções sobre como ativar corretamente esta opção.

Referência do blog: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

Referência da documentação oficial do laravel: https://laravel.com/docs/5.7/migrations


0

Se você estiver criando algo como:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

deveria ser algo como

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

mas você precisa verificar a exclusividade dessa coluna a partir do código ou adicionar uma nova coluna como MD5 ou SHA1 da coluna varchar


3
Então sua chave exclusiva é perdida. Eu acho que a melhor maneira é simplesmente reduzir o comprimento do nome para 191.
haudoing

1
Por que verificar a exclusividade programaticamente se é um recurso nativo do banco de dados?
Paweł Tomkiel

0

Devido a limitações de prefixo, este erro ocorrerá. 767 bytes é a limitação de prefixo declarada para tabelas InnoDB nas versões MySQL anteriores à 5.7. Tem 1.000 bytes de comprimento para tabelas MyISAM. No MySQL versão 5.7 e superior, esse limite foi aumentado para 3072 bytes.

A execução do seguinte no serviço que fornece o erro deve resolver o problema. Isso deve ser executado na CLI MYSQL.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

-1

Altere CHARSET do campo de índice reclamante para "latin1",
isto é, ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1 leva um byte para um caractere em vez de quatro


5
E se ele tentar inserir caracteres não latin1 ?
Paweł Tomkiel

4
Esta é a pior coisa a fazer. Nunca faça isso.
Sebas

1
no meu caso, está em uma coluna que armazena nomes de caminhos com apenas caracteres hexadecimais ... então isso pode ser uma solução para alguém. ele realmente depende do que você deseja armazenar ...
codewandler

Eu tive que rebaixar isso, pois usar latin1 não é uma solução no 2016AD. Eu ainda tenho pesadelos horríveis sobre o tempo que tivemos para converter um banco de dados de latin1 para utf8 em 2007. Ugh. Feio. Em absoluto.
precisa

Eu tive o mesmo problema em um índice exclusivo em duas colunas onde armazeno endereços de bitcoin e IDs de transação. Sempre serão caracteres ASCII, então usarei latin1 nessas colunas. Voto a favor.
alexg

-2

Se você mudou innodb_log_file_sizerecentemente, tente restaurar o valor anterior que funcionou.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.