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


563

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 column1 y column2:

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?

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

55
Debido a que no son 520 bytes, sino más bien 2080 bytes, que superan con creces los 767 bytes, podría hacer column1 varchar (20) y column2 varchar (170). si quieres un equiv de carácter / byte, usa
latin1

3
Creo que tu cálculo está un poco mal aquí. mysql usa 1 o 2 bytes adicionales para registrar la longitud de los valores: 1 byte si la longitud máxima de la columna es 255 bytes o menos, 2 si es más larga que 255 bytes. la codificación utf8_general_ci necesita 3 bytes por carácter, por lo que varchar (20) usa 61 bytes, varchar (500) usa 1502 bytes en total 1563 bytes
lackovic10

3
mysql> seleccione maxlen, character_set_name de information_schema.character_sets donde character_set_name en ('latin1', 'utf8', 'utf8mb4'); maxlen | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
lackovic10

15
'si quieres un equiv de carácter / byte, usa latin1' Por favor , no hagas esto . Latin1 realmente, realmente apesta. Te arrepentirás de esto.
Stijn de Witt

Consulte stackoverflow.com/a/52778785/2137210 para la solución
Pratik,

Respuestas:


490

767 bytes es la limitación de prefijo establecida para las 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 gran campo char o varchar que está codificado en utf8mb4, debe dividir la longitud máxima del prefijo del índice de 767 bytes (o 3072 bytes) por 4, lo que resulta en 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 total, es decir:

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

Realice los ajustes necesarios 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 alcanzar la limitación de MySQL.


44
Para aplicar especificando un subconjunto de la columna en lugar de la cantidad completa. Una buena solucion.
Steven

204204
Esto no explica por qué los campos muy por debajo del límite de longitud exceden el límite de longitud ...
Cerin

66
He intentado editar en la información que falta @Cerin arriba, que claramente consideraba que otros también la faltaban, pero se rechaza por ser más adecuada como comentario. Para aquellos que intentan entender por qué 500 + 20> 767, vea el comentario de Stefan Endrullis sobre la respuesta de Julien.
Letharion

8
Esto puede ser un problema. Por ejemplo: tengo el nombre del campo (255) y agrego un nombre único a este campo en el nombre (191) ya que estoy usando utf8mb4. Si tengo mi usuario agregue su nombre con 'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ...'OJJy' a su el otro su usuario. Debe pasar la validación no atascada en la entrada duplicada.
vee

28
El límite del índice es de 767 bytes , no de caracteres. Y dado que el utf8mb4conjunto de caracteres de Mysql (que el resto del mundo llama utf8) necesita (como máximo) 4 bytes por carácter que solo puede indexar VARCHAR(191). El utf8conjunto de caracteres de Mysql (que el resto del mundo llama roto) necesita como máximo 3 bytes por carácter, por lo que si está usando eso (que no debería ), puede indexar hastaVARCHAR(255)
Stijn de Witt

404

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


247
El número de caracteres permitidos solo depende de su conjunto de caracteres. UTF8 puede usar hasta 3 bytes por carácter, utf8mb4 hasta 4 bytes y latin1 solo 1 byte. Por lo tanto, para utf8, la longitud de su clave está limitada a 255 caracteres desde entonces 3*255 = 765 < 767.
Stefan Endrullis

10
Esto me ahorró mucha frustración, gracias. Debería ser la respuesta aceptada IMO, teniendo en cuenta que el usuario está usando InnoDB alegando que alcanzó una limitación de 767b.
TheCarver

8
Como dijo Stefan Endrullis, depende del juego de caracteres. Si usa UTF8 que usa 3 bytes: 255x3 = 765, que es más bajo que el límite de 767, mientras que 256x3 = 768, que es más alto. Pero si usa UTF8mb4 es 255 * 4 = 1020, por lo que no es una solución
real

25
Esta respuesta es correcta. Sin embargo, si 255 realmente funciona para usted, significa que está utilizando Mysql utf8, que desafortunadamente no funciona. Solo puede codificar caracteres en el plano multilingüe básico. Obtendrá problemas con los personajes que quedan fuera de eso. Por ejemplo, creo que esos personajes Emoji que han estado agregando quedan fuera. Entonces, en lugar de cambiar a VARCHAR(255), cambie a VARCHAR(191) y cambie la codificación a utf8mb4(que en realidad es solo utf8, pero MySql quería mantener atrás. Compat).
Stijn de Witt

1
No es útil para mi restricción única de varias columnas. Tampoco funcionaría para la restricción única de varias columnas del OP. (le daría un tamaño total de 825 bytes)
Barett

352

Cuando llegas al límite. Establecer lo siguiente.

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

34
Esta es la mejor respuesta. Simple, directo al punto y también incluye utf8mb4límite (que es la codificación más utilizada para las bases de datos más nuevas, ya que acepta emojis / etc.).
Claudio Holanda

10
porque 767/4 ~ = 191 y 767/3 ~ = 255
Contador م

11
¿Dónde y cómo configurarlo?
Dinesh Sunny

1
Sí, especificando ENGINE=InnoDB DEFAULT CHARSET=utf8al final de la CREATE TABLEdeclaración pude tener una VARCHAR(255)clave primaria. Gracias.
xonya

1
alguien le da +1 para exceder el límite 191 :)
cagcak

147

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á 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.

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


44
- Lo que presumiblemente significa que cuando uso utf8mb4, necesito establecerlos en (como máximo) 191 como 191 * 4 = 764 <767.
Isaac

2
@Isaac Sí, exactamente,
morganwahl

2
Creo que esta podría ser la respuesta correcta, pero ¿podría explicar qué necesitaría hacer para corregir tal problema? ¿Al menos para los novatos de MySQL como yo?
Adam Grant

No hay una sola forma de evitar este límite de índice. La pregunta aquí es sobre restricciones únicas; para esos, puede tener una columna de texto de longitud ilimitada, y otra donde almacena un hash (como MD5) de ese texto, y usa la columna hash para su restricción única. Tendrá que asegurarse de que su programa mantenga los hash actualizados cuando altere el texto, pero hay varias formas de manejarlo sin demasiados problemas. Francamente, MySQL debería implementar tal cosa en sí misma para que no tenga que hacerlo; No me sorprendería si MariaDB tiene algo así incorporado.
morganwahl

Un índice único en una columna varchar muy larga es raro. Piensa por qué lo necesitas porque podría ser un problema de diseño. Si solo desea un índice en él para la búsqueda, considere algunos campos de 'palabras clave' que caben dentro de 191 caracteres, o divida el texto en una descripción corta y texto largo / completo, etc. O si realmente necesita una búsqueda de texto completo, considere usar un software especializado para como Apache Lucene.
Stijn de Witt

56

ejecute esta consulta antes de su consulta:

SET @@global.innodb_large_prefix = 1;

esto aumentará el límite a 3072 bytes.


44
¿Hay algún inconveniente en cambiar a innodb_large_prefix a nivel mundial? ¿Y ese DB es "global" o todos los DB TOTALMENTE GLOBALES?
SciPhi

55
Solo se aplica cuando se utilizan formatos de fila no estándar. Ver dev.mysql.com/doc/refman/5.5/en/… . Específicamente, 'Habilite esta opción para permitir prefijos de clave de índice de más de 767 bytes (hasta 3072 bytes), para tablas InnoDB que usan los formatos de fila DINÁMICO y COMPRIMIDO'. El formato de fila predeterminado no se ve afectado.
Chris Lear

55
Esto funcionó bien para mí: más detalles y una guía se pueden encontrar aquí: mechanics.flite.com/blog/2014/07/29/…
cwd

1
¿Necesitamos reiniciar el servidor mysql después de esto?
SimpleGuy

77
Importantes detalles faltantes de esta respuesta. innodb_file_formatdebe estar BARRACUDAy en el nivel de la tabla que tiene que usar ROW_FORMAT=DYNAMICo ROW_FORMAT=COMPRESSED. Vea el comentario de @ cwd arriba con la guía.
q0rban

46

Solución para el marco de Laravel

Según la documentación de Laravel 5.4. * ; Debe establecer la longitud de cadena predeterminada dentro del bootmétodo del app/Providers/AppServiceProvider.phparchivo 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 utf8mb4conjunto de caracteres 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 Schema::defaultStringLengthmétodo dentro de su AppServiceProvider.

Alternativamente, puede habilitar la innodb_large_prefixopción 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.


10
@BojanPetkovic Bueno, acabo de llegar de un problema de Laravel, y esta respuesta realmente resolvió mi problema.
mkmnstr

Esta respuesta es genial. Pero, ¿alguien sabe por qué funciona exactamente esto?
UeliDeSchwert

1
La documentación de @Bobby Laravel da su explicación en el encabezado "Longitudes de índice y MySQL / MariaDB" laravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat

1
@Bobby He actualizado la respuesta. He agregado la explicación dada por la documentación de laravel para esta solución.
Ali Shaukat

39

¿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.


8
Si es UTF8, un carácter puede usar hasta 4 bytes, de modo que la columna de 20 caracteres es 20 * 4 + 1bytes y la columna de 500 caracteres es 500 * 4 + 2bytes
Thanatos

55
Por lo que vale, acabo de tener el mismo problema y cambiar de utf8_general_ci a utf8_unicode_ci resolvió el problema para mí. Sin embargo, no sé por qué :(
Andresch Serj

11
Para una VARCHAR(256)columna con un UNIQUEíndice, el cambio de colación no tuvo ningún efecto para mí, como lo hizo para @Andresch. Sin embargo, reducir la longitud de 256 a 255 lo resolvió. No entiendo por qué, ya que 767 / max 4 bytes por carácter produciría un máximo de 191.
Arjan

10
255*3 = 765; 256*3 = 768. Parece que su servidor suponía 3 bytes por carácter, @Arjan
Ámbar

21
@Greg: Tienes razón, pero esto debe ser elaborado: el UTF-8 en sí usa de 1 a 4 bytes por punto de código. Los "juegos de caracteres" de MySQL (realmente codificaciones) tienen un juego de caracteres llamado "utf8" que puede codificar algunos de UTF-8, y usa 1–3 bytes por punto de código, y es incapaz de codificar puntos de código fuera del BMP. También incluye otro juego de caracteres llamado "utf8mb4", que utiliza 1–4 bytes por punto de código y es capaz de codificar todos los puntos de código Unicode. (utf8mb4 es UTF-8, utf8 es una versión extraña de UTF-8.)
Thanatos

28

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, lo que es más de lo permitido 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. Usar codificación "más barata" (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é el latin1_general_cique usa solo un byte por carácter y entonces la columna puede tener 767 bytes de longitud.
  2. Cree hash de 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 UNIQUEclave 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.

Esto hizo el truco. He tenido varchar (256) y tuve que cambiarlo a varchar (250).
MaRmAR

25

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 desde este enlace .

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

Base de datos cambiada

  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 facilitar la administración. > Seleccionar base de datos> Ver estructura de tabla > Ir a la pestaña Operaciones . > Cambie ROW_FORMAT a DYNAMIC y guarde los cambios.
  2. Vaya a la pestaña de estructura de la tabla > Haga clic en el botón Único .
  3. Hecho. 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í.


si aún tiene un error después de ingresar la consulta anterior, intente ir a "phpmyadmin"> establezca la "intercalación" a su preferencia (para mí uso "utf8_general_ci")> haga clic en aplicar (incluso si ya es utf8)
Anthony Kal

No estoy usando una herramienta que funcione con sus instrucciones, pero todavía la estoy votando por tratar de ayudar a las personas a solucionar el problema. Hay infinitas explicaciones de las causas del problema, pero muy poco sobre cómo resolverlo.
Teekin

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

Recibió ese mensaje porque 1 byte equivale a 1 carácter solo si usa el latin-1conjunto de caracteres. Si usa utf8, cada carácter se considerará 3 bytes al definir su columna clave. Si lo 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.


17

Reemplace utf8mb4con utf8en su archivo de importación.

ingrese la descripción de la imagen aquí


¿Por qué exactamente uno debería hacer eso? Además, si esto tiene algún inconveniente (que supongo), debe mencionar esto
Nico Haase,

16

podría agregar una columna de md5 de columnas largas


Tenga en cuenta que esto no le permitirá realizar escaneos de rango en estas columnas. La longitud de los prefijos en los VARCHAR le permitirá mantener este rasgo, al tiempo que puede causar posibles coincidencias espurias en el índice (y el escaneo y la búsqueda de filas para eliminarlos) (vea la respuesta aceptada). (Este es esencialmente un índice hash implementado manualmente, que lamentablemente MysQL no admite con tablas InnoDB.)
Thanatos

No pude usar índices de prefijo porque necesitaba mantener la compatibilidad con H2 para fines de prueba, y descubrí que usar una columna hash funciona bien. Recomiendo encarecidamente utilizar una función resistente a colisiones como SHA1 en lugar de MD5 para evitar que usuarios malintencionados creen colisiones. Una colisión de índice podría explotarse para filtrar datos si una de sus consultas solo verifica el valor hash y no el valor de la columna completa.
Pequeño Mike

13

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

Es absolutamente capaz de agregar índices regulares para VARCHAR(255)campos usando utf8mb4, pero lo que sucede es que el tamaño del índice se trunca en 191 caracteres automáticamente, como unique_keyaquí:

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 los í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 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 de 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.


11

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 conjunto de caracteres utf8(o utf8mb4), con columnas VARCHAR que tienen más de una cierta longitud de caracteres. En el caso de utf8mb4, esa cierta longitud 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


Resuelto el problema para la configuración de las reuniones abiertas (Por cierto, salvaste mi noche :-)
Ludo

11

5 soluciones alternativas:

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


10

Solucioné este problema con:

varchar(200) 

reemplazadas con

varchar(191)

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


Esto es lo que funcionó para mí también. Tuve un varchar (250), pero los datos nunca fueron tan largos. Lo cambió a varchar (100). Gracias por la idea :)
Arun Basil Lal

7

Hice una búsqueda sobre este tema, finalmente obtuve un cambio personalizado

Para MySQL workbench 6.3.7 Versión está disponible la interfase gráfica

  1. Inicie Workbench y seleccione la conexión.
  2. Vaya a administració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. Vaya al director donde está instalado el servidor mysql La mayoría de los casos está en "C: \ Archivos de programa \ MySQL \ MySQL Server 5.7 \ bin", por lo que el comando es "cd \" "Archivos de programa cd \ MySQL \ MySQL Server 5.7 \ bin".
  3. Ahora ejecute el comando mysql -u userName -p databasecheema Ahora solicitó la contraseña del usuario respectivo. Proporcione la contraseña e ingrese en el indicador mysql.
  4. Tenemos que establecer algunas configuraciones globales, ingrese los siguientes comandos uno por uno set innodb_large_prefix = on global; establecer global innodb_file_format = barracuda; establecer global innodb_file_per_table = true;
  5. Ahora, por último, tenemos que alterar el ROW_FORMAT de la tabla requerida por defecto su COMPACT, tenemos que configurarlo en DYNAMIC.
  6. use el siguiente comando alter table table_name ROW_FORMAT = DYNAMIC;
  7. Hecho

No puedo encontrar esto: 6. establezca el valor de la opción innodb_default_row_format en DYNAMIC.
Adrian Cid Almaguer

si lo uso set global innodb_default_row_format = DYNAMIC;, veo este mensaje: ERROR 1193 (HY000): variable de sistema desconocida 'innodb_default_row_format'
Adrian Cid Almaguer

¿Cómo obtuviste un error de workbench a cmd? Lo hice desde workbench tiene opción directamente.
Abhishek

Lo hago desde CMD porque no veo la opción en Workbench
Adrian Cid Almaguer

1
Veo el problema que esta var se introdujo en v5.7.9 y tengo la versión v5.6.33, gracias
Adrian Cid Almaguer

7

Para laravel 5.7 a 6.0

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 Agregar esto Schema::defaultStringLength(191);

Que todo, disfruta.


Trabajó para Laravel 5.8 también.
Neo

Esta es una mala solución. Motivo: los índices no están destinados a ser infinitamente largos. Cuando aplica un índice único a algo, desea que el índice se arregle la mayor parte del tiempo. Eso significa que NO DEBERÍAS hacer cosas como emailúnicas, pero debes hacer un hash del correo electrónico y hacerlo único. A diferencia de los datos de cadena sin procesar, los hashes son de ancho fijo y pueden indexarse ​​y hacerse únicos sin problemas. En lugar de entender el problema, estás difundiendo prácticas horribles que no escalan.
NB

5

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


"Casi" es una pista bastante buena de que esta no es una solución a largo plazo
Nico Haase

4

Solo cambiar utf8mb4a la utf8hora de 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;.


4

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

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Confirmo que mi problema también fue la recopilación de la base de datos. No tengo ninguna explicación para eso. Uso mysql v5.6.32 y la clasificación de DB fue utf8mb4_unicode_ci.
mahyard

2

Según la columna que se muestra a continuación, esas 2 columnas de cadena variable están usando la utf8_general_ciclasificación (utf8 conjunto de caracteres está implícito).

En MySQL, utf8charset 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 obtienes este error 1071.

En otras palabras, debe calcular el recuento de caracteres en función de la representación de bytes del conjunto de caracteres, ya que no todos los conjuntos de caracteres son una representación de un solo byte (como suponía). IE utf8en MySQL se utiliza como máximo 3 bytes por carácter, 767 / 3≈255 caracteres, y para utf8mb4, como máximo, una representación de 4 bytes, 767 / 4≈191 caracteres.

También se sabe que MySQL

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

1

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

1

Por favor, compruebe si sql_modees 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

1

En mi caso, tuve este problema cuando estaba haciendo una copia de seguridad de una base de datos usando los caracteres de salida / entrada 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 el> redireccionamiento)

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

Restaurar (sin la <redirección)

# 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" simplemente desapareció.


1

Longitudes de índice y MySQL / MariaDB


Laravel utiliza el conjunto de caracteres utf8mb4 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 del blog: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

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


0

Si estás 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 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


3
Entonces tu clave única se perdió. Creo que la mejor manera es simplemente reducir la longitud del nombre a 191.
haudoing

1
¿Por qué verificar la unicidad mediante programación si es una característica nativa de DB?
Paweł Tomkiel

0

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;

-1

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


55
¿Y qué pasa si intenta insertar caracteres no latin1 ?
Paweł Tomkiel

44
Esta es la peor cosa que hacer. Nunca hagas eso.
Sebas

1
en mi caso está en una columna que almacena nombres de ruta con solo caracteres hexadecimales ... por lo que esta podría ser una solución para alguien. realmente depende de lo que quieras almacenar ...
codewandler

Tuve que rechazar esto, ya que usar latin1 no es una solución en 2016AD. Todavía tengo pesadillas horribles sobre el tiempo que tuvimos para convertir una base de datos de latin1 a utf8 en 2007. Ugh. No es bonito. En absoluto.
Apuesta lanzada el

Tuve el mismo problema en un índice único en dos columnas donde almaceno direcciones de bitcoin e ID de transacciones. Estos siempre serán caracteres ASCII, por lo que usaré latin1 en estas columnas. Votación a favor.
alexg

-2

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.