# 1071 - La clave especificada era demasiado larga; la longitud máxima de la clave es de 767 bytes

StackOverflow https://stackoverflow.com/questions/1814532

Pregunta

Cuando ejecuté el siguiente comando:

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

Recibí este mensaje de error:

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

Información sobre columna1 y columna2:

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

Creo que varchar(20) solo requiere 21 bytes mientras que varchar(500) solo requiere 501 bytes. Entonces, los bytes totales son 522, menos de 767. Entonces, ¿por qué recibí el mensaje de error?

<*>
¿Fue útil?

Solución

767 bytes es la limitación de prefijo establecida para Tablas InnoDB en MySQL versión 5.6 (y versiones anteriores). Tiene 1,000 bytes de largo para las tablas MyISAM. En MySQL versión 5.7 y superiores, este límite se ha incrementado a 3072 bytes.

También debe tener en cuenta que si establece un índice en un campo char o varchar grande codificado en utf8mb4, debe dividir la longitud máxima del prefijo del índice de 767 bytes (o 3072 bytes) por 4, lo que da como resultado 191. Esto se debe a que la longitud máxima de un carácter utf8mb4 es de cuatro bytes. Para un carácter utf8, serían tres bytes, lo que daría como resultado una longitud máxima de prefijo de índice de 254.

Una opción que tiene es simplemente colocar un límite inferior en sus campos VARCHAR.

Otra opción (de acuerdo con la respuesta a este problema ) es obtener el subconjunto de la columna en lugar de la cantidad completa, es decir:

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

Modifique según sea necesario para obtener la clave para aplicar, pero me pregunto si valdría la pena revisar su modelo de datos con respecto a esta entidad para ver si hay mejoras que le permitan implementar las reglas comerciales previstas sin llegar a MySQL limitación.

Otros consejos

Si alguien tiene problemas con INNODB / Utf-8 tratando de poner un índice UNIQUE en un campo VARCHAR(256), cámbielo a VARCHAR(255). Parece que 255 es la limitación.

Cuando llegas al límite. Establezca lo siguiente.

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

MySQL supone el peor de los casos para el número de bytes por carácter en la cadena. Para la codificación 'utf8' de MySQL, son 3 bytes por carácter, ya que esa codificación no permite caracteres más allá de U+FFFF. Para la codificación 'utf8mb4' de MySQL, son 4 bytes por carácter, ya que eso es lo que MySQL llama UTF-8 real.

Entonces, suponiendo que esté usando 'utf8', su primera columna tomará 60 bytes del índice, y su segunda otra 1500.

ejecute esta consulta antes de su consulta:

SET @@global.innodb_large_prefix = 1;

esto aumentará el límite a 3072 bytes.

¿Qué codificación de caracteres estás usando? Algunos conjuntos de caracteres (como UTF-16, etc.) usan más de un byte por carácter.

Solución para Laravel Framework

Según Laravel 5.4. * documentación ; Debe establecer la longitud de cadena predeterminada dentro del método boot del archivo app/Providers/AppServiceProvider.php de la siguiente manera:

use Illuminate\Support\Facades\Schema;

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

Explicación de esta corrección, dada por Laravel 5.4. * documentación :

  

Laravel usa el conjunto de caracteres utf8mb4 por defecto, que incluye soporte para almacenar " emojis " en la base de datos Si está ejecutando una versión de MySQL anterior a la versión 5.7.7 o MariaDB anterior a la versión 10.2.2, es posible que deba configurar manualmente la longitud de cadena predeterminada generada por las migraciones para que MySQL cree índices para ellos. Puede configurar esto llamando al método Schema::defaultStringLength dentro de su AppServiceProvider.

     

Alternativamente, puede habilitar la opción innodb_large_prefix para su   base de datos. Consulte la documentación de su base de datos para obtener instrucciones sobre   cómo habilitar correctamente esta opción.

  

Creo que varchar (20) solo requiere 21 bytes mientras que varchar (500) solo   requiere 501 bytes. Entonces, los bytes totales son 522, menos de 767. Entonces, ¿por qué?   ¿Recibí el mensaje de error?

UTF8 requiere 3 bytes por carácter para almacenar la cadena, por lo que en su caso 20 + 500 caracteres = 20 * 3 + 500 * 3 = 1560 bytes que son < strong> más de permitidos 767 bytes.

El límite para UTF8 es 767/3 = 255 caracteres , para UTF8mb4 que usa 4 bytes por carácter es 767/4 = 191 caracteres.


Hay dos soluciones a este problema si necesita usar una columna más larga que el límite:

  1. Use " más barato " codificación (la que requiere menos bytes por carácter)
    En mi caso, necesitaba agregar un índice único en la columna que contiene la cadena SEO del artículo, ya que solo uso [A-z0-9\-] caracteres para SEO, utilicé latin1_general_ci que usa solo un byte por carácter y, por lo tanto, la columna puede tener una longitud de 767 bytes.
  2. Cree hash desde su columna y use un índice único solo en eso
    La otra opción para mí era crear otra columna que almacenara hash de SEO, esta columna tendría la tecla UNIQUE para garantizar que los valores de SEO sean únicos. También agregaría KEY índice a la columna SEO original para acelerar la búsqueda.

La respuesta sobre por qué recibes un mensaje de error ya fue respondida por muchos usuarios aquí. Mi respuesta es sobre cómo solucionarlo y usarlo como está.

Consulte este enlace .

  1. Abra el cliente MySQL (o el cliente MariaDB). Es una herramienta de línea de comandos.
  2. Le pedirá su contraseña, ingrese su contraseña correcta.
  3. Seleccione su base de datos con este comando use my_database_name;
  

La base de datos ha cambiado

  1. set global innodb_large_prefix=on;
  

Consulta OK, 0 filas afectadas (0.00 seg)

  1. set global innodb_file_format=Barracuda;
  

Consulta OK, 0 filas afectadas (0.02 segundos)

  1. Vaya a su base de datos en phpMyAdmin o algo así para una fácil administración. > Seleccione la base de datos & Gt; Ver tabla estructura & Gt; Vaya a la pestaña Operaciones . > Cambie ROW_FORMAT a DYNAMIC y guarde los cambios.
  2. Ir a la tabla estructura pestaña > Haga clic en el botón Único .
  3. Listo. Ahora no debería tener errores.

El problema de esta solución es si exporta db a otro servidor (por ejemplo, de localhost a host real) y no puede usar la línea de comando MySQL en ese servidor. No puedes hacer que funcione allí.

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

Recibió ese mensaje porque 1 byte equivale a 1 carácter solo si utiliza el conjunto de caracteres latin-1. Si usa utf8, cada carácter se considerará 3 bytes al definir su columna clave. Si usa utf8mb4, se considerará que cada carácter tiene 4 bytes al definir su columna clave. Por lo tanto, debe multiplicar el límite de caracteres de su campo clave por 1, 3 o 4 (en mi ejemplo) para determinar la cantidad de bytes que el campo clave está tratando de permitir. Si está utilizando uft8mb4, solo puede definir 191 caracteres para un campo de clave primaria nativo, InnoDB. Simplemente no infrinja 767 bytes.

puede agregar una columna de md5 de columnas largas

Encontramos este problema al intentar agregar un índice ÚNICO a un campo VARCHAR (255) usando utf8mb4. Si bien el problema ya se describe bien aquí, quería agregar algunos consejos prácticos sobre cómo resolvimos esto y lo resolvimos.

Cuando se usa utf8mb4, los caracteres cuentan como 4 bytes, mientras que bajo utf8, pueden tener 3 bytes. Las bases de datos de InnoDB tienen un límite que los índices solo pueden contener 767 bytes. Entonces, cuando use utf8, puede almacenar 255 caracteres (767/3 = 255), pero usando utf8mb4, solo puede almacenar 191 caracteres (767/4 = 191).

Puede agregar índices regulares para los campos VARCHAR(255) usando utf8mb4, pero lo que sucede es que el tamaño del índice se trunca en 191 caracteres automáticamente, como unique_key aquí:

 Captura de pantalla de Sequel Pro que muestra el índice truncado a 191 caracteres

Esto está bien, porque los índices regulares solo se usan para ayudar a MySQL a buscar sus datos más rápidamente. No es necesario indexar todo el campo.

Entonces, ¿por qué MySQL trunca el índice automáticamente para índices regulares, pero arroja un error explícito al intentar hacerlo para índices únicos? Bueno, para que MySQL pueda determinar si el valor que se está insertando o actualizando ya existe, necesita indexar todo el valor y no solo una parte de él.

Al final del día, si desea tener un índice único en un campo, todo el contenido del campo debe caber en el índice. Para utf8mb4, esto significa reducir las longitudes de campo VARCHAR a 191 caracteres o menos. Si no necesita utf8mb4 para esa tabla o campo, puede soltarlo nuevamente a utf8 y mantener sus 255 campos de longitud.

Aquí está mi respuesta original:

  

Acabo de soltar la base de datos y recrear así, y el error desapareció:

     

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

Sin embargo, no funciona para todos los casos.

En realidad, es un problema usar índices en columnas VARCHAR con el juego de caracteres utf8 (o utf8mb4), con columnas VARCHAR que tienen más de una cierta longitud de caracteres. En el caso de <=>, esa longitud determinada es 191.

Consulte la sección Índice largo de este artículo para obtener más información sobre cómo usar índices largos en la base de datos MySQL: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- conjunto de caracteres a utf8mb4

Hice una búsqueda en este tema y finalmente obtuve un cambio personalizado

Para MySQL workbench 6.3.7 Versión entre fases gráfica está disponible

  1. Inicie Workbench y seleccione la conexión.
  2. Vaya a gestión o Instancia y seleccione Archivo de opciones.
  3. Si Workbench le pide permiso para leer el archivo de configuración y luego lo permite presionando OK dos veces.
  4. En el centro, aparece la ventana del archivo de opciones del administrador.
  5. Vaya a la pestaña InnoDB y verifique el innodb_large_prefix si no está marcado en la sección General.
  6. establezca el valor de la opción innodb_default_row_format en DYNAMIC.

Para las versiones a continuación 6.3.7, las opciones directas no están disponibles, por lo que debe ir con el símbolo del sistema

  1. Inicie CMD como administrador.
  2. Ir al director donde se instala el servidor mysql La mayoría de los casos es en " C: \ Archivos de programa \ MySQL \ MySQL Server 5.7 \ bin " entonces el comando es " cd \ " " cd Archivos de programa \ MySQL \ MySQL Server 5.7 \ bin " ;.
  3. Ahora ejecutar comando mysql -u nombre de usuario -p bases de datoscheema Ahora solicitó la contraseña del usuario respectivo. Proporcione la contraseña e ingrese en mysql prompt.
  4. Tenemos que establecer algunas configuraciones globales, ingrese los siguientes comandos uno por uno establecer global innodb_large_prefix = on; establecer global innodb_file_format = barracuda; set global innodb_file_per_table = true;
  5. Ahora, al final, tenemos que alterar el ROW_FORMAT de la tabla requerida de manera predeterminada, su COMPACT, tenemos que establecerlo en DYNAMIC.
  6. usa el siguiente comando alter table table_name ROW_FORMAT = DYNAMIC;
  7. Listo

Solucioné este problema con:

varchar(200) 

reemplazado con

varchar(191)

todos los varchar que tienen más de 200 los reemplazan por 191 o los configuran como texto.

5 soluciones:

El límite se elevó en 5.7.7 (MariaDB 10.2.2?). Y se puede aumentar con algo de trabajo en 5.6 (10.1).

Si está llegando al límite por intentar usar CHARACTER SET utf8mb4. Luego, realice una de las siguientes acciones (cada una tiene un inconveniente) para evitar el error:

⚈  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

cambia tu colación. Puede usar utf8_general_ci que admite casi todos

Simplemente cambiar utf8mb4 a utf8 al crear tablas resolvió mi problema. Por ejemplo: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; a CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.

Para laravel 5.7 o 5.6 o 5.8

Pasos a seguir

  1. Ir a App\Providers\AppServiceProvider.php.
  2. Agregue esto al proveedor use Illuminate\Support\Facades\Schema; en la parte superior.
  3. Dentro de la función de arranque Agregue esto Schema::defaultStringLength(191);

que todo, disfruta.

De acuerdo con la columna que se proporciona a continuación, esas 2 columnas de cadena variable están usando utf8_general_ci intercalación (utf8 juego de caracteres está implícito).

En MySQL, utf8mb4 charset usa un máximo de 3 bytes para cada carácter. Por lo tanto, necesitaría asignar 500 * 3 = 1500 bytes, que es mucho mayor que los 767 bytes que permite MySQL. Es por eso que está recibiendo este error 1071.

En otras palabras, debe calcular el recuento de caracteres en función de la representación de bytes del juego de caracteres, ya que no todos los juegos de caracteres son una representación de un solo byte (como suponía). I.E. <=> en MySQL se utiliza como máximo 3 bytes por carácter, 767/3 & # 8776; 255 caracteres, y para <=>, una representación como máximo de 4 bytes, 767/4 & # 8776; 191 caracteres.

También se sabe que MySQL

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

Encontré esta consulta útil para detectar qué columnas tenían un índice que violaba la longitud máxima:

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')

Compruebe si sql_mode es como

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

si es así, cambie a

sql_mode=NO_ENGINE_SUBSTITUTION

O

reinicie su servidor cambiando su archivo my.cnf (poniendo lo siguiente)

innodb_large_prefix=on

En mi caso, tuve este problema cuando hacía una copia de seguridad de una base de datos usando los caracteres de entrada / salida de redirección de Linux. Por lo tanto, cambio la sintaxis como se describe a continuación. PD: usando un terminal Linux o Mac.

Copia de seguridad (sin > redirigir)

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

Restaurar (sin < redirigir)

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

El error " La clave especificada era demasiado larga; la longitud máxima de la clave es 767 bytes " simple desaparecido.

Longitudes de índice & amp; MySQL / MariaDB


Laravel utiliza el carácter utf8mb4 configurado de forma predeterminada, que incluye soporte para almacenar " emojis " en la base de datos. Si está ejecutando una versión de MySQL anterior a la versión 5.7.7 o MariaDB anterior a la versión 10.2.2, es posible que deba configurar manualmente la longitud de cadena predeterminada generada por las migraciones para que MySQL cree índices para ellos. Puede configurar esto llamando al método Schema :: defaultStringLength dentro de su AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Alternativamente, puede habilitar la opción innodb_large_prefix para su base de datos. Consulte la documentación de su base de datos para obtener instrucciones sobre cómo habilitar esta opción correctamente.

Referencia de la documentación oficial de laravel: https://laravel.com/ docs / 5.7 / migrations

Cambie CHARSET del campo de índice de queja a " latin1 "
es decir, ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1 toma un byte para un carácter en lugar de cuatro

Si está creando 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;

debería ser algo así 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;

pero debe verificar la unicidad de esa columna desde el código o agregar una nueva columna como MD5 o SHA1 de la columna varchar

Debido a las limitaciones del prefijo, se producirá este error. 767 bytes es la limitación de prefijo establecida para las tablas InnoDB en las versiones de MySQL anteriores a 5.7. Tiene 1,000 bytes de largo para las tablas MyISAM. En MySQL versión 5.7 y superiores, este límite se ha incrementado a 3072 bytes.

Ejecutar lo siguiente en el servicio que le da el error debería resolver su problema. Esto debe ejecutarse en la CLI de MYSQL.

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

Para solucionar eso, esto funciona para mí como un encanto.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Si ha cambiado innodb_log_file_size recientemente, intente restaurar el valor anterior que funcionó.

Para mí, el problema de " # 1071 - La clave especificada era demasiado larga; la longitud máxima de la clave es 767 bytes " se resolvió después de cambiar la combinación de clave principal / clave única limitando el tamaño de la columna a 200.

ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top