Pergunta

Quando eu executei o seguinte comando:

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

Eu tenho essa mensagem de erro:

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

As informações sobre column1 e column2:

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

Eu acho varchar(20) requer apenas 21 bytes, enquanto varchar(500) requer apenas 501 bytes. Assim, os bytes totais são 522, menos de 767. Então, por que eu recebo a mensagem de erro?

#1071 - Specified key was too long; max key length is 767 bytes
Foi útil?

Solução

767 bytes é o indicado prefixo limitação para tabelas InnoDB no MySQL versão 5.6 (e versões anteriores). É 1.000 bytes para tabelas MyISAM. Na versão MySQL 5.7 e acima deste limite foi aumentado para 3072 bytes.

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

Uma opção que você tem é apenas lugar limite inferior em seus campos VARCHAR.

Outra opção (de acordo com a a esta questão ) é obter o subconjunto da coluna em vez de toda a quantidade, isto é:

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

Tweak que você precisa para obter a chave de aplicar, mas eu me pergunto se seria vale a pena rever o seu modelo de dados em relação a esta entidade para ver se há melhorias que lhe permitem implementar as regras de negócios pretendidos sem bater o MySQL limitação.

Outras dicas

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

Quando você atinge o limite. Definir o seguinte.

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

MySQL assume pior caso para o número de bytes por caractere na seqüência. Para o MySQL 'utf8' codificação, que é 3 bytes por caractere, uma vez que a codificação não permite caracteres além U+FFFF. Para o MySQL 'utf8mb4' codificação, é 4 bytes por caractere, já que é o MySQL chamadas reais UTF-8.

Assim, supondo que você está usando 'utf8', sua primeira coluna terá 60 bytes do índice, e seu segundo outra 1500.

executar esta consulta antes de sua consulta:

SET @@global.innodb_large_prefix = 1;

isso vai aumentar limite para 3072 bytes.

O que codificação de caracteres que você está usando? Alguns conjuntos de caracteres (como, et cetera UTF-16) usar mais de um byte por caractere.

Solução Para Laravel Framework

De acordo com Laravel 5.4 * documentação .; Você tem que definir o comprimento da corda padrão dentro do método boot do arquivo app/Providers/AppServiceProvider.php da seguinte forma:

use Illuminate\Support\Facades\Schema;

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

Explicação dessa correção, dada por Laravel 5.4. * Documentação :

Laravel usa o conjunto de caracteres utf8mb4 por padrão, que inclui suporte para o armazenamento "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 da corda padrão gerado pelas migrações, a fim de MySQL para criar índices para eles. Você pode configurar esta chamando o método Schema::defaultStringLength dentro do seu AppServiceProvider.

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

Eu acho que varchar (20) requer apenas 21 bytes, enquanto varchar (500), apenas requer 501 bytes. Assim, os bytes totais são 522, menos de 767. Então, por que eu recebi a mensagem de erro?

UTF8 requer 3 bytes por caractere para armazenar o string, então no seu caso 20 + 500 caracteres = 20 * 3 + 500 * 3 = 1560 bytes que é < forte> mais do que permitido 767 bytes.

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


Há duas soluções para esse problema se você precisa usar mais de coluna do que o limite:

  1. Use "mais barato" encoding (o que requer menos bytes por caractere)
    No meu caso, eu precisava para adicionar único índice na coluna contendo seqüência de SEO do artigo, como eu usar apenas caracteres [A-z0-9\-] para SEO, eu usei latin1_general_ci que usa apenas um byte por caractere e assim coluna pode ter 767 bytes de comprimento.
  2. Criar de hash de sua coluna e use índice exclusivo somente naquele
    A outra opção para mim foi a de criar uma outra coluna que iria armazenar hash do SEO, esta coluna teria tecla UNIQUE para assegurar valores de SEO são únicos. Gostaria de acrescentar também índice KEY a coluna SEO original para acelerar a olhar para cima.

A resposta sobre por que você receber a mensagem de erro já foi respondido por muitos usuários aqui. Minha resposta é sobre como corrigir e usá-lo como ele é.

Consulte a partir este link .

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

Banco de Dados mudou

  1. set global innodb_large_prefix=on;

Query OK, 0 linhas afetadas (0,00 segundos)

  1. set global innodb_file_format=Barracuda;

Query OK, 0 linhas afectado (0,02 s)

  1. Vá para o seu banco de dados sobre phpMyAdmin ou algo parecido para fácil gerenciamento. > Selecionar banco de dados> Ver tabela estrutura > Vá para Operações . > Alterar ROW_FORMAT para DYNAMIC e salvar alterações.
  2. Vá para tabela Estrutura tab> Clique em Único botão.
  3. Concluído. Agora deve não tem erros.

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

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

Você tem essa mensagem porque 1 byte é igual a 1 personagem só se você usar o conjunto de caracteres latin-1. Se você usar utf8, cada personagem será considerada 3 bytes ao definir a sua coluna de chave. Se você usar utf8mb4, cada personagem será considerado 4 bytes ao definir a sua coluna de chave. Assim, você precisa multiplicar limite de caracteres do seu campo de chave por, 1, 3, ou 4 (no meu exemplo) para determinar o número de bytes o campo chave está tentando permitir. Se você estiver usando uft8mb4, você só pode definir 191 caracteres para um, InnoDB, campo de chave primária nativa. Só não violar 767 bytes.

você pode adicionar uma coluna do md5 de longas colunas

Nós encontrou este problema ao tentar adicionar um índice UNIQUE a um VARCHAR (255) campo usando utf8mb4. Enquanto o problema é descrito bem aqui já, eu queria acrescentar alguns conselhos práticos de como nós entendemos isso e resolveu.

Ao usar utf8mb4, personagens contam como 4 bytes, enquanto que sob utf8, eles poderiam até 3 bytes. bases de dados InnoDB tem um limite que os índices podem conter apenas 767 bytes. Então, quando usando utf8, você pode armazenar 255 caracteres (767/3 = 255), mas utilizando utf8mb4, você só pode armazenar 191 caracteres (767/4 = 191).

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

 Sequel Pro imagem mostrando índice truncado em 191 caracteres

Isso é bom, porque os índices regulares são usados ??apenas para procure ajuda MySQL através de seus dados mais rapidamente. O campo inteiro não precisa ser indexado.

Então, por que MySQL truncar o índice automaticamente para índices regulares, mas lançar um erro explícita ao tentar fazê-lo por índices únicos? Bem, para o MySQL para ser capaz de descobrir se o valor que está sendo inserido ou já atualizados existe, ele precisa realmente índice de todo o valor e não apenas parte dela.

No final do dia, se você quiser ter um índice exclusivo em um campo, todo o conteúdo do campo deve se encaixar no índice. Para utf8mb4, isso significa reduzir seus comprimentos de campo VARCHAR 191 caracteres ou menos. Se você não precisa utf8mb4 para essa tabela ou no campo, você pode cair de volta para utf8 e ser capaz de manter seus 255 campos de comprimento.

Aqui está a minha resposta original:

Eu apenas uma gota de banco de dados e recriar como este, e o erro se foi:

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

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

Na verdade, é um problema do uso de índices em colunas VARCHAR com o utf8 conjunto de caracteres (ou utf8mb4), com colunas VARCHAR que têm mais de um determinado comprimento de caracteres. No caso de utf8mb4, que determinado comprimento é 191.

Por favor, consulte a seção Índice de Longo neste artigo para obter mais informações como usar índices longos no banco de dados MySQL: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- character-set-to-utf8mb4

Eu fiz alguma pesquisa sobre este tema finalmente alguma mudança feita sob encomenda

Para o MySQL Workbench 6.3.7 versão gráfica entre fase está disponível

  1. Inicie o Workbench e selecione a conexão.
  2. Vá para a gestão ou instância e selecione Opções do arquivo.
  3. Se Workbench pedir-lhe permissão para ler arquivo de configuração e, em seguida, permitir que ele pressionando OK duas vezes.
  4. Na janela arquivo de opções do administrador do centro lugar vem.
  5. guia Ir para InnoDB e verificar a innodb_large_prefix se não verificada na seção Geral.
  6. set innodb_default_row_format valor opção para dinâmico.

Para versões abaixo 6.3.7 opções diretas não estão disponíveis para necessidade de ir com prompt de comando

  1. Iniciar CMD como administrador.
  2. Go To diretor, onde servidor mysql é instalar maioria dos casos, a sua em "C: \ Program Files \ MySQL \ MySQL Servidor 5.7 \ bin" para comando é "Cd \" "Cd Program Files \ MySQL \ MySQL Servidor 5.7 \ bin".
  3. comando Agora Run mysql -uNome_do_Usuário -p databasescheema Agora é solicitado para a senha do respectivo usuário. Fornecer a senha e entrar no prompt mysql.
  4. Nós temos que definir algumas configurações globais entrar no abaixo comandos, um por um definir innodb_large_prefix mundial = on; conjunto global innodb_file_format = barracuda; conjunto global innodb_file_per_table = true;
  5. Agora, no último, temos de alterar a ROW_FORMAT da tabela necessária por padrão sua COMPACT temos que configurá-lo para dinâmico.
  6. uso seguinte comando ALTER TABLE table_name ROW_FORMAT = dinâmico;
  7. Concluído

Eu reparei esta questão com:

varchar(200) 

substituído com

varchar(191)

todo o varchar que têm mais de 200 substituí-los por 191 ou defini-los texto.

5 soluções alternativas:

O limite foi criado em 5.7.7 (MariaDB 10.2.2?). E isso pode ser aumentada com algum trabalho em 5,6 (10,1).

Se você está atingindo o limite por causa de tentar usar CHARACTER SET utf8mb4. Em seguida, faça um dos seguintes (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

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

Apenas mudando utf8mb4 para utf8 quando as tabelas criando resolveu o meu problema. Por exemplo:. CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; para CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Para laravel 5.7 ou 5.6 ou 5.8

Passos para seguido

  1. Vá para App\Providers\AppServiceProvider.php.
  2. Adicione isto a use Illuminate\Support\Facades\Schema; provedor na parte superior.
  3. Dentro da função Boot Adicionar esta Schema::defaultStringLength(191);

que tudo, desfrutar.

Com base na coluna dada abaixo, esses 2 colunas de cadeia variáveis ??são usando utf8_general_ci agrupamento (utf8 conjunto de caracteres está implícito).

Em MySQL, utf8 charset usa um máximo de 3 bytes para cada personagem. Deste modo, seria necessário para alocar 500 * 3 = 1500 bytes, que é muito maior do que a 767 bytes MySQL permite. É por isso que você está recebendo este erro 1071.

Em outras palavras, você precisa calcular a contagem de caracteres com base na representação byte do charset como nem todos os charset é uma única representação byte (como você presumido.) OU SEJA utf8 no MySQL é usos no máximo de 3 bytes por caracter, 767 / 3˜255 caracteres, e para utf8mb4, um, no máximo, a representação de 4 bytes, 767 / 4˜191 caracteres.

É também conhecido que o MySQL

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

Eu encontrei esta consulta útil na detecção de quais colunas tinha um índice violar 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')

Verifique se sql_mode é como

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

se for, mude para

sql_mode=NO_ENGINE_SUBSTITUTION

ou

reiniciar o servidor mudar seu my.cnf arquivo (colocando seguinte)

innodb_large_prefix=on

No meu caso, eu tive esse problema quando eu estava fazendo backup de um banco de dados usando os caracteres de saída / entrada linux redirecionamento. Portanto, eu alterar a sintaxe tal como descrito abaixo. PS:. Utilizando um terminal Linux ou Mac

Backup (sem a> redirecionamento)

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

Restaurar (sem o

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

O erro "chave especificado era demasiado longo, comprimento de chave máximo é 767 bytes" simples desapareceu

.

Índice Lengths & MySQL / MariaDB


Laravel usa o caractere utf8mb4 set por padrão, que inclui suporte para o armazenamento de "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 da corda padrão gerado pelas migrações, a fim de MySQL para criar índices para eles. Você pode configurar esta chamando o Schema :: defaultStringLength método dentro de sua 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 adequadamente esta opção.

Referência de Documentação oficial laravel: https://laravel.com/ docs / 5.7 / migrações

Alterar CHARSET do campo de índice reclamando para "latin1"
isto é ALTER TABLE tbl MUDANÇA myfield myfield VARCHAR (600) CHARACTER SET PADRÃO latin1 NULL;
latin1 leva um byte para um caractere em vez de quatro

Se você está 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;

deve 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 singularidade dessa coluna a partir do código ou adicionar uma nova coluna como MD5 ou SHA1 da coluna varchar

Devido a limitações de prefixo este erro ocorrerá. 767 bytes é o prefixo limitação indicada para tabelas InnoDB em versões MySQL antes de 5,7. É 1.000 bytes para tabelas MyISAM. Na versão MySQL 5.7 e acima deste limite foi aumentado para 3072 bytes.

executando o seguinte sobre o serviço que lhe dá o erro deve resolver o problema. Este tem de ser executado no CLI do MySQL.

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

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

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Se você tiver alterado innodb_log_file_size recentemente, tente restaurar o valor anterior que funcionou.

Para mim, a questão da "# 1071 - Chave especificada era muito longo; comprimento de chave máximo é 767 bytes" ficou resolvido depois de mudar a combinação primarykey / uniquekey, limitando o tamanho da coluna em 200

.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top