2009-12-01 43 views
258

Tengo una tabla con una clave primaria que es varchar (255). Han surgido algunos casos en que 255 caracteres no son suficientes. He intentado cambiar el campo a un texto, pero me sale el siguiente error:Error de MySQL: especificación de clave sin longitud de clave

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

cómo puedo solucionar este problema?

editar: Debo señalar también que esta tabla tiene una clave primaria compuesta con varias columnas.

+8

Una tabla no puede tener varias claves principales. ¿Quiere decir que tiene una clave primaria compuesta (que incluye más de una columna) o tiene varias claves 'ÚNICAS'? – Quassnoi

+0

En mi caso, por algún motivo, tenía un tipo de TEXTO para una columna de correo electrónico en lugar de VARCHAR. – Kris

Respuesta

424

El error ocurre porque MySQL puede indexar solo los primeros N caracteres de una columna BLOB o TEXT. Por lo que el error se produce principalmente cuando hay un tipo de campo/columna de TEXT o BLOB o los que pertenecen a TEXT o BLOB tipos, tales como TINYBLOB, MEDIUMBLOB, LONGBLOB, TINYTEXT, MEDIUMTEXT, y LONGTEXT que intenta hacer una clave principal o un índice. Con total BLOB o TEXT sin el valor de longitud, MySQL no puede garantizar la exclusividad de la columna ya que es de tamaño variable y dinámico. Por lo tanto, cuando se usan los tipos BLOB o TEXT como índice, se debe proporcionar el valor de N para que MySQL pueda determinar la longitud de la clave. Sin embargo, MySQL no admite un límite de longitud de clave en TEXT o BLOB. TEXT(88) simplemente no funcionará.

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

La solución al problema es eliminar la columna TEXT o BLOB del índice o restricción única o establecer otro campo como clave principal. Si no puede hacer eso, y quiere poner un límite en la columna TEXT o BLOB, intente utilizar el tipo VARCHAR y coloque un límite de longitud en él. De forma predeterminada, 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 de longitud solamente.

A veces, aunque no utilice el tipo relacionado con TEXT o BLOB en su tabla, también puede aparecer el error 1170. Sucede en una situación como cuando especifica la columna VARCHAR como clave principal, pero configura erróneamente su longitud o tamaño de caracteres. VARCHAR solo acepta hasta 256 caracteres, por lo que cualquier cosa como VARCHAR(512) obligará a MySQL a autoconvertir el VARCHAR(512) en un tipo de datos SMALLTEXT, que posteriormente falla con el error 1170 en la longitud de la clave si la columna se utiliza como clave principal o única o no índice único. Para resolver este problema, especifique una cifra inferior a 256 como el tamaño para el campo VARCHAR.

Referencia: MySQL Error 1170 (42000): BLOB/TEXT Column Used in Key Specification Without a Key Length

+11

http://dev.mysql.com/doc/refman/5.0/en/char.html "Los valores en las columnas VARCHAR son cadenas de longitud variable. La longitud se puede especificar como un valor de 0 a 255 antes de MySQL 5.0 .3 y de 0 a 65,535 en 5.0.3 y versiones posteriores. La longitud máxima efectiva de un VARCHAR en MySQL 5.0.3 y posterior está sujeta al tamaño máximo de fila (65.535 bytes, que se comparte entre todas las columnas) " – umassthrower

+1

Donde dices "MySQL puede indexar solo los primeros N caracteres de una columna BLOB o TEXT", ¿cuál es el valor de N? – jameshfisher

+0

"Cuando indexa una columna BLOB o TEXT, debe especificar una longitud de prefijo para el índice". http://dev.mysql.com/doc/refman/5.6/en/column-indexes.html –

62

Debe definir lo que conduce porción de una columna TEXT desea indexar.

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

Esto funciona muy 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 juego de caracteres de la columna. Es 767 caracteres para un juego de caracteres de un solo byte como LATIN1 y sólo 255 caracteres para UTF8 (MySQL sólo se utiliza BMP que requiere como máximo 3 bytes por carácter)

Si necesita toda la columna sea el PRIMARY KEY, calcular SHA1 o MD5 hash y utilícelo como PRIMARY KEY.

+0

Exactamente lo que estaba buscando. ¡Gracias! –

+0

¿El tamaño (255 aquí) está realmente en caracteres y no en bytes? Porque podría imaginar que usar caracteres para UTF-8 sería realmente complicado sin ningún beneficio adicional. –

+0

Lo siento, no sigo su pregunta. De los documentos: * El límite de longitud del prefijo de la clave del índice es de 767 bytes para las tablas InnoDB que usan el formato de fila 'REDUNDANTE' o' COMPACT'. Por ejemplo, puede alcanzar este límite con un índice de prefijo de columna de más de 255 caracteres en una columna 'TEXT' o' VARCHAR', asumiendo un conjunto de caracteres utf8mb3 y el máximo de 3 bytes para cada carácter. * 'REDUNDANT' y' COMPACT' fueron los únicos formatos disponibles en el momento en que se dio esta respuesta. – Quassnoi

1

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

47

se puede especificar la longitud de la clave en la solicitud de modificación de tabla, algo así como:

alter table authors ADD UNIQUE(name_first(20), name_second(20)); 
+1

Esto era exactamente lo que * I * necesitaba para solucionar el mismo problema. ¡Gracias! –

+2

¡Debe tener mucho cuidado con este enfoque! Esta es quizás la solución más fácil, pero en situaciones de lotes no es la mejor. Su clave consta de dos columnas y el orden de las columnas es importante. – MrD

3

no tienen valores largos como clave primaria. Eso destruirá tu rendimiento. Consulte el manual de mysql, sección 13.6.13 'Ajuste y solución de problemas de rendimiento InnoDB'.

En su lugar, tiene una clave int subrogada como primaria (con auto_increment), y su clave loong como UNIQUE secundaria.

0

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

1

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

+1

También debe tener mucho cuidado con cadenas completamente "aleatorias", como las producidas por MD5(), SHA1() o UUID(). Cada nuevo valor que genere con ellos se distribuirá de forma arbitraria en un espacio grande, lo que puede ralentizar INSERT y algunos tipos de consultas SELECT: – MrD

+1

La distribución de MD5, SHA1 sobre datos no maliciosos debe ser uniforme --- eso es lo que son los hashes para. –

14

MySQL no permite la indexación de un valor total de BLOB, TEXT y largas columnas VARCHAR porque los datos que contienen puede ser enorme, e implícitamente índice de base de datos será grande, lo que significa ningún beneficio de índice.

MySQL requiere que defina los primeros N caracteres para indexar, y el truco consiste en 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 que el índice sea tan útil como lo sería si hubiera indexado toda la columna.

Antes de ir más allá, déjenos definir algunos términos importantes. La selectividad del índice es la proporción de los valores indizados distintos totales y el número total de filas. Aquí está un ejemplo de tabla de prueba:

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

Si índice sólo el primer carácter (N = 1), entonces la mesa de índice se parecerá a la siguiente tabla:

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

En este caso, el índice la selectividad 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 mayor selectividad índice, pero también hemos aumentado el tamaño de índice. El truco es encontrar el número mínimo N que resultará en una selectividad de índice máxima.

Existen dos métodos para hacer cálculos para la tabla de la base de datos. Haré una demostración en el this database dump.

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

Primera permitió establecer las 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 se puede ver, el último nombre de Baba es la más frecuente. Ahora vamos a encontrar los prefijos de last_name más frecuentes, comenzando con los 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 mucho más ocurrencias de cada prefijo, que significa que tenemos para aumentar el número N hasta que los valores son casi los mismos que en el ejemplo anterior.

Aquí hay 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í hay 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 un índice en la columna last_name con indexación de los primeros 10 caracteres. En la definición de 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 alrededor de 9 KB, e imagine cómo crecería este número si nuestra tabla contiene millones de filas.

Puede leer otras formas de calcular el número de N en mi publicación Prefixed indexes in MySQL.

+1

Esto no se ha actualizado lo suficiente. Descubrí que es *** mucho más fácil de entender que la respuesta aceptada – Mawg

0

La solución al problema es que en su instrucción CREATE TABLE, puede agregar la restricción UNIQUE (problemtextfield(300)) después de que la columna cree definiciones para especificar una longitud key de 300 caracteres para un TEXT campo, por ejemplo.Entonces los primeros caracteres 300 del campo problemtextfieldTEXT tendrían que ser únicos, y las diferencias posteriores se descartarían.

Cuestiones relacionadas