Error de MySQL: especificación de clave sin una longitud de clave


Tengo una tabla con una clave primaria que es un varchar(255). Algunos casos han surgido donde 255 caracteres no es suficiente. Intenté cambiar el campo a un texto, pero obtengo el siguiente error:

BLOB/TEXT column 'message_id' used in key specification without a key length

¿Cómo puedo arreglar esto?

Editar: También debo señalar que esta tabla tiene una clave primaria compuesta con múltiples columnas.

Author: Spencer Wieczorek, 2009-12-01

13 answers

El error ocurre porque MySQL puede indexar solo los primeros N caracteres de un BLOB o columna TEXT. Por lo tanto, el error ocurre principalmente cuando hay un tipo de campo/columna de TEXT o BLOB o aquellos que pertenecen a TEXT o BLOB tipos como TINYBLOB, MEDIUMBLOB, LONGBLOB, TINYTEXT, MEDIUMTEXT, y LONGTEXT que trates de hacer una clave primaria o índice. Con BLOB completo o TEXT sin el valor de longitud, MySQL no puede garantizar la singularidad de la columna ya que es de tamaño variable y dinámico. Por lo tanto, al usar BLOB o TEXT tipos como índice, el valor de N debe ser suministrado para que MySQL pueda determinar la longitud de la clave. Sin embargo, MySQL no soporta un límite de longitud de clave en TEXT o BLOB. TEXT(88) simplemente no funcionará.

El error también aparecerá cuando intente convertir una columna de tabla de tipo non-TEXT y non-BLOB como VARCHAR y ENUM en tipo TEXT o BLOB, con la columna ya definida como restricciones únicas o índice. El comando Alter Table SQL fallará.

La solución al problema es eliminar la columna TEXT o BLOB de la restricción index o unique o establecer otro campo como clave primaria. Si no puede hacer eso, y desea colocar un límite en la columna TEXT o BLOB, intente usar VARCHAR type y coloque un límite de longitud en ella. Por defecto, VARCHAR está limitado a un máximo de 255 caracteres y su límite debe especificarse implícitamente dentro de un corchete justo después de su declaración, es decir, VARCHAR(200) lo limitará a 200 caracteres solamente.

A veces, a pesar de que no utilice TEXT o BLOB tipo relacionado en la tabla, el Error 1170 también puede aparecer. Sucede en una situación como cuando se especifica la columna VARCHAR como clave primaria, pero se establece erróneamente su longitud o tamaño de caracteres. VARCHAR solo puede aceptar hasta 256 caracteres, por lo que cualquier cosa como VARCHAR(512) forzará a MySQL a convertir automáticamente el VARCHAR(512) a un tipo de datos SMALLTEXT, que posteriormente falla con el error 1170 en la longitud de la clave si la columna se usa como clave primaria o índice único o no único. Para resolver este problema, especifique una cifra inferior a 256 como el tamaño del campo VARCHAR.

Referencia: Error MySQL 1170 (42000): Columna BLOB/TEXTO Utilizada en la Especificación de Clave Sin una Longitud de Clave

 454
Author: OMG Ponies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-03 08:18:26

Debe definir qué porción inicial de una columna TEXT desea indexar.

InnoDB tiene una limitación de 768 bytes por clave de índice y no podrá crear un índice más largo que eso.

Esto funcionará bien:

CREATE TABLE t_length (
      mydata TEXT NOT NULL,
      KEY ix_length_mydata (mydata(255)))
    ENGINE=InnoDB;

Tenga en cuenta que el valor máximo del tamaño de la clave depende del conjunto de caracteres de columna. Es 767 caracteres para un conjunto de caracteres de un solo byte como LATIN1 y solo 255 caracteres para UTF8 (MySQL solo usa BMP que requiere como máximo 3 bytes por carácter)

Si necesitas que toda tu columna sea PRIMARY KEY, calcula SHA1 o MD5 hash y úsalo como PRIMARY KEY.

 66
Author: Quassnoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-11 19:31:58

Puede especificar la longitud de la clave en la solicitud alter table, algo así como:

alter table authors ADD UNIQUE(name_first(20), name_second(20));
 51
Author: Mike Evans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 16:51:08

MySQL no permite indexar un valor completo de BLOB, TEXT y largas VARCHAR columnas porque los datos que contienen pueden ser enormes, e implícitamente el índice DB será grande, lo que significa que no hay beneficio del índice.

MySQL requiere que defina los primeros N caracteres para ser indexados, y el truco es elegir un número N que sea lo suficientemente largo como para dar una buena selectividad, pero lo suficientemente corto como para ahorrar espacio. El prefijo debe ser lo suficientemente largo como para hacer que el índice sea casi tan útil como lo sería si hubiera indexado el todo columna.

Antes de ir más allá, definamos algunos términos importantes. La selectividad del índicees la relación entre los valores indizados distintos totales y el número total de filas. Aquí hay un ejemplo para la tabla de prueba:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

Si indexamos solo el primer carácter (N=1), entonces la tabla índice se verá como la siguiente tabla:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

En este caso, la selectividad del índice es igual a IS=1/3 = 0.33.

Veamos ahora qué sucederá si aumentamos el número de caracteres indexados a dos (N = 2).

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

En este escenario ES=2/3=0.66 lo que significa que aumentamos la selectividad del índice, pero también hemos aumentado el tamaño del índice. El truco es encontrar el número mínimo N que resultará en la selectividad máxima del índice .

Hay dos enfoques que puede hacer cálculos para su tabla de base de datos. Voy a hacer una demostración en el este volcado de base de datos.

Digamos que queremos agregar la columna last_name en la tabla empleadosal índice, y queremos definir el número más pequeño N que producirá la mejor selectividad del índice.

Primero identifiquemos los apellidos más frecuentes:

select count(*) as cnt, last_name 
from employees 
group by employees.last_name 
order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

Como pueden ver, el apellido Baba es el más frecuente. Ahora vamos a encontrar los prefijos last_name más frecuentes, comenzando con prefijos de cinco letras.

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

Hay muchas más ocurrencias de cada prefijo, que significa que tenemos que aumentar el número N hasta que los valores sean casi los mismos que en el ejemplo anterior.

Aquí están los resultados para N = 9

select count(*) as cnt, left(last_name,9) as prefix 
from employees 
group by prefix 
order by cnt desc 
limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

Aquí están los resultados para N=10.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

Estos son muy buenos resultados. Esto significa que podemos hacer índice en la columna last_name con indexación de solo los primeros 10 caracteres. En la definición de la tabla, la columna last_name se define como VARCHAR(16), y esto significa que hemos guardado 6 bytes (o más si hay caracteres UTF8 en el apellido) por entrada. En esta tabla hay 1637 valores distintos multiplicados por 6 bytes es de aproximadamente 9 KB, e imaginar cómo este número crecería si nuestra tabla contiene millones de filas.

Puedes leer otras formas de calcular el número de N en mi post Índices prefijados en MySQL.

 16
Author: MrD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-13 19:47:00
alter table authors ADD UNIQUE(name_first(767), name_second(767));

NOTA : 767 es el número de caracteres límite hasta el cual MySQL indexará las columnas al tratar con índices blob/text

Ref: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

 4
Author: Abhishek Goel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-06 11:02:10

No tienen valores largos como clave primaria. Eso destruirá tu rendimiento. Consulte el manual de mysql, sección 13.6.13 'InnoDB Performance Tuning and Troubleshooting'.

En su lugar, tenga una clave int sustituta como primaria (con auto_increment), y su clave loong como ÚNICA secundaria.

 3
Author: Per Lindberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-01 10:29:49

Otra excelente manera de lidiar con esto es crear su campo de TEXTO sin la restricción única y agregar un campo VARCHAR hermano que sea único y contenga un resumen (MD5, SHA1, etc.).) del campo de TEXTO. Calcule y almacene el resumen sobre todo el campo de TEXTO cuando inserta o actualiza el campo de TEXTO, tiene una restricción de singularidad sobre todo el campo de TEXTO (en lugar de alguna parte principal) que se puede buscar rápidamente.

 2
Author: par,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-22 18:08:53

Agregue otra columna varChar(255) (con el valor predeterminado como cadena vacía no null) para mantener el desbordamiento cuando 255 caracteres no son suficientes, y cambie este PK para usar ambas columnas. Sin embargo, esto no suena como un esquema de base de datos bien diseñado, y recomendaría que un modelador de datos vea lo que tiene con el fin de refactorizarlo para una mayor Normalización.

 1
Author: Charles Bretana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-01 16:01:10

Además, si desea utilizar index en este campo, debe utilizar el motor de almacenamiento MyISAM y el tipo de índice de texto COMPLETO.

 0
Author: Alexander Valinurov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-17 10:52:08

La solución al problema es que en su instrucción CREATE TABLE, puede agregar la restricción UNIQUE ( problemtextfield(300) ) después de la columna crear definiciones para especificar una longitud key de caracteres 300 para un campo TEXT, por ejemplo. Entonces los primeros 300 caracteres de la problemtextfield TEXT el campo tendría que ser único, y cualquier diferencia después de eso no se tendría en cuenta.

 0
Author: Who Dunnit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-10 00:44:07

Use así

@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;
 0
Author: Krishna Das,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 07:14:30

Tienes que cambiar el tipo de columna a varchar o integer para indexar.

 0
Author: Manoj Mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-20 12:39:04

Vaya a mysql edit table -> cambie el tipo de columna a varchar(45).

 0
Author: Manoj Mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-20 14:00:27