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
mysql
byte
varchar
mysql-error-1071
Steven
fuente
fuente
Respuestas:
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:
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.
fuente
utf8mb4
conjunto de caracteres de Mysql (que el resto del mundo llama utf8) necesita (como máximo) 4 bytes por carácter que solo puede indexarVARCHAR(191)
. Elutf8
conjunto 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)
Si alguien tiene problemas con INNODB / Utf-8 tratando de poner un
UNIQUE
índice en unVARCHAR(256)
campo, cámbielo aVARCHAR(255)
. Parece 255 es la limitación.fuente
3*255 = 765 < 767
.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 aVARCHAR(255)
, cambie aVARCHAR(191)
y cambie la codificación autf8mb4
(que en realidad es solo utf8, pero MySql quería mantener atrás. Compat).Cuando llegas al límite. Establecer lo siguiente.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
fuente
utf8mb4
límite (que es la codificación más utilizada para las bases de datos más nuevas, ya que acepta emojis / etc.).ENGINE=InnoDB DEFAULT CHARSET=utf8
al final de laCREATE TABLE
declaración pude tener unaVARCHAR(255)
clave primaria. Gracias.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.
fuente
ejecute esta consulta antes de su consulta:
esto aumentará el límite a
3072 bytes
.fuente
innodb_file_format
debe estarBARRACUDA
y en el nivel de la tabla que tiene que usarROW_FORMAT=DYNAMIC
oROW_FORMAT=COMPRESSED
. Vea el comentario de @ cwd arriba con la guía.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
boot
método delapp/Providers/AppServiceProvider.php
archivo de la siguiente manera:Explicación de esta corrección, dada por Laravel 5.4. * Documentación :
fuente
¿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.
fuente
20 * 4 + 1
bytes y la columna de 500 caracteres es500 * 4 + 2
bytesVARCHAR(256)
columna con unUNIQUE
í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.255*3 = 765; 256*3 = 768
. Parece que su servidor suponía 3 bytes por carácter, @ArjanUTF8 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:
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é ellatin1_general_ci
que usa solo un byte por carácter y entonces la columna puede tener 767 bytes de longitud.La otra opción para mí era crear otra columna que almacenara hash de SEO, esta columna tendría
UNIQUE
clave para garantizar que los valores de SEO sean únicos. También agregaríaKEY
índice a la columna SEO original para acelerar la búsqueda.fuente
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 .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
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í.
fuente
Recibió ese mensaje porque 1 byte equivale a 1 carácter solo si usa el
latin-1
conjunto de caracteres. Si usautf8
, cada carácter se considerará 3 bytes al definir su columna clave. Si lo usautf8mb4
, 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.fuente
Reemplace
utf8mb4
conutf8
en su archivo de importación.fuente
podría agregar una columna de md5 de columnas largas
fuente
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, comounique_key
aquí: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.
fuente
Aquí está mi respuesta original:
Sin embargo, no funciona para todos los casos.
En realidad, es un problema usar índices en columnas VARCHAR con el conjunto de caracteres
utf8
(outf8mb4
), con columnas VARCHAR que tienen más de una cierta longitud de caracteres. En el caso deutf8mb4
, 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
fuente
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:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
fuente
Solucioné este problema con:
reemplazadas con
todos los varchar que tienen más de 200 los reemplazan por 191 o los configuran como texto.
fuente
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
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
fuente
set global innodb_default_row_format = DYNAMIC;
, veo este mensaje: ERROR 1193 (HY000): variable de sistema desconocida 'innodb_default_row_format'Para laravel 5.7 a 6.0
Pasos a seguir
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
en la parte superior.Schema::defaultStringLength(191);
Que todo, disfruta.
fuente
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.cambia tu colación. Puede usar utf8_general_ci que admite casi todos
fuente
Solo cambiar
utf8mb4
a lautf8
hora de crear tablas resolvió mi problema. Por ejemplo:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
aCREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.fuente
Para arreglar eso, esto funciona para mí como un encanto.
fuente
Según la columna que se muestra a continuación, esas 2 columnas de cadena variable están usando la
utf8_general_ci
clasificación (utf8
conjunto de caracteres está implícito).En MySQL,
utf8
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 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
utf8
en MySQL se utiliza como máximo 3 bytes por carácter, 767 / 3≈255 caracteres, y parautf8mb4
, como máximo, una representación de 4 bytes, 767 / 4≈191 caracteres.También se sabe que MySQL
fuente
Encontré esta consulta útil para detectar qué columnas tenían un índice que violaba la longitud máxima:
fuente
Por favor, compruebe si
sql_mode
es comosi es así, cambie a
O
reinicie su servidor cambiando su archivo my.cnf (poniendo lo siguiente)
fuente
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)
Restaurar (sin la <redirección)
El error "La clave especificada era demasiado larga; la longitud máxima de la clave es 767 bytes" simplemente desapareció.
fuente
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:
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
fuente
Si estás creando algo como:
debería ser algo como
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
fuente
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.
fuente
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
fuente
Si ha cambiado
innodb_log_file_size
recientemente, intente restaurar el valor anterior que funcionó.fuente