2010-05-07 17 views
32

Un compañero de trabajo me hizo conocer un comportamiento MySQL muy extraño.¿Por qué el aumento automático de MySQL aumenta en las inserciones fallidas?

Suponiendo que tiene una tabla con un campo auto_increment y otro campo que se establece en único (por ejemplo, un campo de nombre de usuario). Al intentar insertar una fila con un nombre de usuario que ya está en la tabla, la inserción falla, como se esperaba. Sin embargo, el valor de auto_increment aumenta como se puede ver cuando inserta una nueva entrada válida después de varios intentos fallidos.

Por ejemplo, cuando nuestra última entrada se parece a esto ...

ID: 10 
Username: myname 

... y tratamos cinco nuevas entradas con el mismo valor de nombre de usuario en nuestra próxima inserción habremos creado una nueva fila como por lo que:

ID: 16 
Username: mynewname 

Si bien esto no es un gran problema en sí mismo parece como un vector de ataque muy tonto para matar a una mesa inundándolo con las solicitudes de inserción fallidos, como los MySQL Reference Manual establece:

"El comportamiento del mecanismo de autoincremento no se define [...] si el valor es mayor que el entero máximo que se puede almacenar en el tipo de entero especificado".

¿Este comportamiento es esperado?

+6

Su vector de ataque parece un no tema. Si pudiera inundarlo con solicitudes de inserción fallidas, ¿no podría igualmente inundarlo con solicitudes no fallidas? –

+0

¿Puedes traer un ** código ** de reproducción en lugar de explicaciones manuales? –

+4

@martin smith: Si bien es cierto, creo que un aumento repentino de nuevos usuarios sería más obvio que un aumento silencioso en el autoincremento que muy bien podría quedarse en el camino si no se verifica. – Sorcy

Respuesta

23

InnoDB es un motor transaccional.

Esto significa que en el siguiente escenario:

  1. Session A insertos registro 1
  2. Session B insertos registro 2
  3. Session A cilindros de

, o bien hay una posibilidad de una brecha o session B se bloquearía hasta el session A cometido o revertido.

InnoDB diseñadores (como la mayoría de los otros diseñadores de motores transaccionales) decidieron dejar huecos.

Desde el documentation:

Al acceder al contador aún, InnoDB utiliza un bloqueo de tabla especial AUTO-INC, que mantiene hasta el final de la actual SQL declaración, no al final de la transacción . La estrategia de bloqueo especial se introdujo para mejorar la concurrencia de inserciones en una tabla que contiene una columna AUTO_INCREMENT

...

InnoDB utiliza el contador de auto incremento en memoria, siempre y cuando se ejecuta el servidor. Cuando el servidor se detiene y se reinicia, InnoDB reinicia el contador de cada tabla para el primer INSERT en la tabla, como se describió anteriormente.

Si usted tiene miedo de la envoltura alrededor de la columna id, que sea BIGINT (8 bytes de longitud).

+1

Su respuesta me ayudó mucho con mi propio problema. Gracias. ¿Hay alguna forma de eludir este comportamiento de InnoDB con respecto a la autoincrementación? – Aufwind

+0

misma pregunta que Aufwind. –

+1

@Ankit: publíquelo como otra pregunta y coloque un enlace aquí. – Quassnoi

4

Sin conocer las partes internas exactas, diría que sí, el autoincremento DEBERÍA permitir que los valores omitidos hagan inserciones de falla. Digamos que está haciendo una transacción bancaria, u otra donde toda la transacción y múltiples registros van como un todo o nada. Si prueba su inserción, obtenga una ID, luego selle todos los detalles subsiguientes con esa ID de transacción e inserte los registros de detalles, debe asegurarse de que su exclusividad calificada. Si tiene varias personas que cierran de golpe la base de datos, ellos también deberán asegurarse de obtener su propia identificación de transacción para no entrar en conflicto con la suya cuando se compromete la transacción. Si algo falla en la primera transacción, no se produce ningún daño ni elementos que cuelguen río abajo.

+0

es el uso de esta naturaleza skkiping de incremento automático, pero quiero saber si esto es una forma de detener este skkiping –

+2

@Ankit, no, no puede detener la omisión. El encabezado del archivo que realiza un seguimiento de la última ID que se asignó siempre se incrementa. Si hay un problema, y ​​10 personas están ingresando transacciones y 3 cancelan, nunca querrá rellenar dicha transacción abortada solo para usar una ID. – DRapp

+0

gracias por limpiar el agujero –

-1

Sé que este es un artículo antiguo, pero como tampoco pude encontrar la respuesta correcta, en realidad encontré la manera de hacerlo. Tienes que ajustar tu consulta dentro de una declaración if. Su menudo introducen consulta o insertar y en querys duplicados que desordenar el orden de incremento automático organizado de tal manera para las inserciones de uso regular:

y en lugar de INSERTAR Y EN DUPLICADO utilizar un conjunto UPDATE WHERE CONSULTA dentro o fuera de una sentencia if no importa y un CAMBIAR eN CONSULTA también parece funcionar

+2

Estoy bajando la votación de esta respuesta, ya que no se aplica en absoluto. Sí, puede verificar si existe un registro antes de probar la inserción, pero eso está completamente fuera del punto. – Mave

Cuestiones relacionadas