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
mysql
byte
varchar
mysql-error-1071
Steven
fonte
fonte
Respostas:
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:
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.
fonte
utf8mb4
conjunto 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)
. Outf8
conjunto 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)
Se alguém estiver tendo problemas com o INNODB / Utf-8 tentando colocar um
UNIQUE
índice em umVARCHAR(256)
campo, mude paraVARCHAR(255)
. Parece 255 é a limitação.fonte
3*255 = 765 < 767
.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 paraVARCHAR(255)
, mude paraVARCHAR(191)
e mude a codificação parautf8mb4
(que na verdade é apenas utf8, mas o MySql queria impedir. Compat).Quando você atinge o limite. Defina o seguinte.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
fonte
utf8mb4
limit (que é a codificação mais usada para bancos de dados mais recentes, pois aceita emojis / etc).ENGINE=InnoDB DEFAULT CHARSET=utf8
no final daCREATE TABLE
declaração que eu consegui ter umaVARCHAR(255)
chave primária. Obrigado.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.
fonte
execute esta consulta antes da sua consulta:
isso aumentará o limite para
3072 bytes
.fonte
innodb_file_format
deve estarBARRACUDA
e No nível da mesa, você deve usarROW_FORMAT=DYNAMIC
ouROW_FORMAT=COMPRESSED
. Veja o comentário do @ cwd acima com o guia.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
boot
método doapp/Providers/AppServiceProvider.php
arquivo da seguinte maneira:Explicação dessa correção, fornecida pela documentação do Laravel 5.4. * :
fonte
Qual codificação de caracteres você está usando? Alguns conjuntos de caracteres (como UTF-16 etc.) usam mais de um byte por caractere.
fonte
20 * 4 + 1
bytes, ea coluna de char 500 é500 * 4 + 2
bytesVARCHAR(256)
coluna com umUNIQUE
í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?255*3 = 765; 256*3 = 768
. Parece que o seu servidor foi asssuming 3 bytes por personagem, @ ArjanO 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:
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, useilatin1_general_ci
que usa apenas um byte por caractere e assim a coluna pode ter 767 bytes de comprimento.A outra opção para mim era criar outra coluna que armazenasse o hash do SEO. Essa coluna teria a
UNIQUE
chave para garantir que os valores do SEO sejam únicos. Eu também adicionaria umKEY
índice à coluna SEO original para acelerar a pesquisa.fonte
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 .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
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á.
fonte
Você recebeu essa mensagem porque 1 byte é igual a 1 caractere apenas se você usar o
latin-1
conjunto de caracteres. Se você usarutf8
, cada caractere será considerado 3 bytes ao definir sua coluna-chave. Se você usarutf8mb4
, 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.fonte
Substitua
utf8mb4
porutf8
no seu arquivo de importação.fonte
você pode adicionar uma coluna do md5 de colunas longas
fonte
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 - comounique_key
aqui: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.
fonte
Aqui está a minha resposta original:
No entanto, não funciona para todos os casos.
Na verdade, é um problema usar índices nas colunas VARCHAR com o conjunto de caracteres
utf8
(ouutf8mb4
), com colunas VARCHAR que possuem mais de um determinado comprimento de caracteres. No caso deutf8mb4
, 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
fonte
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:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
fonte
Corrigi esse problema com:
substituído por
todo o varchar que tem mais de 200 substitui-os por 191 ou os define como texto.
fonte
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
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
fonte
set global innodb_default_row_format = DYNAMIC;
, vejo esta mensagem: ERRO 1193 (HY000): Variável de sistema desconhecida 'innodb_default_row_format'Para laravel 5.7 a 6.0
Passos a seguir
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
no topo.Schema::defaultStringLength(191);
isso tudo, aproveite.
fonte
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.mude seu agrupamento. Você pode usar utf8_general_ci que suporta quase todos
fonte
Apenas mudar
utf8mb4
para autf8
criação de tabelas resolveu meu problema. Por exemplo:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
paraCREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.fonte
Para consertar isso, isso funciona para mim como um encanto.
fonte
Com base na coluna fornecida abaixo, essas duas colunas de sequência variável estão usando
utf8_general_ci
agrupamento (utf8
charset está implícito).No MySQL,
utf8
charset 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
utf8
no MySQL usa no máximo 3 bytes por caractere, 767 / 3≈255 caracteres e, parautf8mb4
, no máximo, uma representação de 4 bytes, 767/4 × 191 caracteres.Também é sabido que o MySQL
fonte
Achei esta consulta útil para detectar quais colunas tinham um índice que viola o comprimento máximo:
fonte
Por favor, verifique se
sql_mode
é comose for, mude para
OU
reinicie o servidor alterando o arquivo my.cnf (colocando a seguir)
fonte
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)
Restaurar (sem o <redirecionamento)
O erro "Chave especificada era muito longa; o comprimento máximo da chave é 767 bytes" simples desapareceu.
fonte
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:
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
fonte
Se você estiver criando algo como:
deveria ser algo como
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
fonte
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.
fonte
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
fonte
Se você mudou
innodb_log_file_size
recentemente, tente restaurar o valor anterior que funcionou.fonte