2011-04-19 20 views
6

Hoy he encontrado una de las cosas más extrañas con MySQL que he visto. Tengo una tabla trivial:incrementos de la columna mysql auto_increment por un valor aleatorio

CREATE TABLE `features` 
(
    `feature_id` mediumint(6) unsigned NOT NULL AUTO_INCREMENT, 
    `feature_name` varchar(100) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL, 
    PRIMARY KEY (`feature_id`), 
    UNIQUE KEY `feature_name_key` (`feature_name`) 
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; 

Estoy insertando los datos dentro de la biblioteca de Java y MySQL-conector-java-5.1.15. Los datos en feature_name pueden duplicarse y solo quiero valores únicos. ¿Puedo usar INSERT IGNORE pero en el caso de datos es demasiado largo se me permite pasar por alto lo que utilizar esto:

pstmt = conn.prepareStatement( 
     "INSERT INTO features (feature_name) VALUES (?)"); 

for (String featureName: data4db.keySet()) 
{ 
    pstmt.setString(1, featureName); 

    try 
    { 
     pstmt.executeUpdate(); 
    } 
    catch (SQLException se) 
    { 
     if (se.getErrorCode() == 1062) // duplicate entry 
     { 
      continue; // ignore 
     } 

     throw se; // do not ignore anything else 
    } 
} 

vez que los datos se ha insertado en db me he dado cuenta de que había algunos problemas que ni siquiera ha esperado . Hay aproximadamente 4000 registros en la tabla de arriba que está bien. El único problema es que algunos datos no se pudieron insertar debido a la clave primaria duplicada, así que he buscado cómo se ven los valores autom inc para esta tabla. Resulta que para la mayoría de los datos, la siguiente identificación de filas adyacentes se incrementó en 1 como se esperaba. Por razones que no sé a veces, feature_id se incrementó en 3, 5, 1000, 100000 - valor completamente aleatorio. Por lo tanto, me he 'quedado sin lugar en esta tabla' ya que no se pudo insertar una vez que id alcanzó max val para medium int.

¿Cómo puede suceder esto? ¿Alguien ha encontrado algo similar? Vale la pena decir que solo había un programa con un hilo escribiendo en esta tabla. Tengo una tabla más casi idéntica: el ancho de las columnas y los nombres son diferentes. Para este hay un problema similar.

cierto - algunos datos más:

mysql> show global variables like 'auto_inc%'; 
+--------------------------+-------+ 
| Variable_name   | Value | 
+--------------------------+-------+ 
| auto_increment_increment | 1  | 
| auto_increment_offset | 1  | 
+--------------------------+-------+ 
2 rows in set (0.01 sec) 

mysql> show global variables like 'ver%'; 
+-------------------------+------------------------------+ 
| Variable_name   | Value      | 
+-------------------------+------------------------------+ 
| version     | 5.5.10      | 
| version_comment   | MySQL Community Server (GPL) | 
| version_compile_machine | x86       | 
| version_compile_os  | Win32      | 
+-------------------------+------------------------------+ 

Gracias por cualquier insinuación de antemano.

Respuesta

10

Es el comportamiento normal de MySQL. Lo que sucedió es lo siguiente: insertó los datos hasta la clave auto_increment 3 y luego obtuvo la clave duplicada ya que su feature_name_key se define como única. La cosa es que MySQL "desperdiciará" el número entero 4 y pasará al siguiente, no reutilizará los enteros que han fallado la escritura debido a la restricción de la clave.

Si tenía algo como esto:

PK | feature_name_key 
1 | key1 
2 | key2 
3 | key3 
4 | key1 (fails due to constraint, 4 is not going to be used for next successful insertion, hence the gaps in your primary key) 

entonces se pierde en números enteros disponibles para la clave primaria/AUTO_INCREMENT. Repensar su estrategia al insertar o construir la tabla para contener sus datos.

+0

Tiene razón. Agradéceme por una lección rápida y muy útil. Lo he comprobado dos veces. Así que, en esencia, el número que es una diferencia entre los identificadores en 2 filas adyacentes indica cuántos intentos de inserción duplicados hubo entre estas 2 filas. – Artur

+0

¿Se puede autoincrementar cuando se encuentra duplicado de alguna manera deshabilitado? ¿Hay alguna solución? Solo quiero tener una tabla con id y una cadena única asignada a ella sin espacios vacíos, pero no quiero usar insert ignore (tiene el mismo problema con autoinc) ni leer toda la tabla antes de insertar para verificar qué valores ya están ¿ahí? ¿Un procedimiento? – Artur

+0

Hay muchas soluciones, pero la pregunta es: ¿por qué quieres identificadores secuenciales? Está utilizando una clave sustituta aquí cuando la clave natural sería una opción mucho mejor desde el punto de vista de la teoría. Puede tener su feature_name_key como clave principal (por lo tanto, la restricción única se impone inmediatamente) y puede crear un desencadenador para actualizar la columna llamada sequence_id y luego puede asignar enteros asignados secuencialmente sin espacios a los nombres de sus características. –

0

Entre las inserciones, ¿ha eliminado las filas? MySQL podría simplemente estar recordando el contador de autoincrement.

+0

sin inserciones solamente - Ya sé la respuesta - gracias – Artur

Cuestiones relacionadas