2010-12-05 21 views
26

Estoy creando un sitio web en el que me gustaría incrementar un contador en una tabla MyISAM estándar.¿Se está incrementando un campo en MySQL atómico?

ejemplo simplificado:

UPDATE votes SET num = num + 1; 

Será esto causar problemas si múltiples conexiones están haciendo la misma consulta, o serán MySQL cuidar de él y bloquear la tabla o algo para asegurarse de que no hay conflictos?

+0

Usted también puede estar interesado en mi respuesta a otra pregunta de bloqueo: http://stackoverflow.com/questions/3312361/does-this-lock -the-database/3312790 # 3312790 – Mike

Respuesta

12

Las tablas MyISAM usan bloqueo de nivel de tabla. Esto significa que toda la tabla se bloqueará durante la ejecución de su consulta de actualización. Entonces, la respuesta para su caso de uso simplificado es: sí, esto es seguro para subprocesos. Pero este puede no ser el caso si usa otro motor de almacenamiento o su actualización incluye varias tablas.

Aquí es una cita del manual de MySQL para más claridad:

tabla de bloqueo permite a muchas sesiones a leídos de una mesa al mismo tiempo, pero si una sesión quiere escribir en una tabla , primero debe obtener acceso exclusivo . Durante la actualización, todas las demás sesiones que deseen acceder a esta tabla particular deben esperar hasta que finalice la actualización .

También puede considerar el uso de columnas de incrementos automáticos, transacciones o sincronización externa si eso se ajusta a su diseño.

¡Salud!

3

Esta forma de UPDATE es atómica. Otras formas de UPDATE se pueden hacer atómicas usando transacciones con SELECT ... FOR UPDATE.

4

Sí, la tabla (o filas en las bases de datos de formato InnoDB) se bloquea automáticamente cuando ejecuta una consulta de actualización.

18

La escritura es atómica pero un incremento también requiere una lectura. Entonces la pregunta es: ¿Estás seguro de que la lectura es segura? En otras palabras, ¿estás seguro de que otro hilo haciendo el incremento no terminará con el mismo valor que se incrementará? Tengo dudas. La forma 100% correcta de hacer esto sería.

-- begin transaction here 

select counter from myCounters where counter_id = 1 FOR UPDATE; 

-- now the row is locked and nobody can read or modify its values 

update myCounters set counter = ? where id = 1; 

-- set ? to counter + 1 programmatically 

commit; -- and unlock... 
+1

Estoy bastante seguro de que el ejemplo OPs de UPDATE SET field = field + 1 no causará ningún problema de concurrencia, pero esta es la mejor manera de asegurarse de que está bloqueando la fila/tabla mientras se modifica un campo Por lo general, tiene más sentido cuando se realiza una operación más compleja. – Nicholi

0

tenían el mismo problema, aunque la consulta era más complicado:

UPDATE CLB_SYNC_T SET PENDING_MESSAGES = PENDING_MESSAGES + ? WHERE USER_ID = ? 

Usando MyISAM como motor predeterminado no ayuda, por lo que vuelve a los SELECT FOR UPDATE uso.

Con SELECCIONE PARA ACTUALIZAR el rendimiento mejoró ~ 10 veces, ya que MySQL no bloqueó toda la tabla, para hacer una actualización de fila.

0

Otro enfoque al utilizar InnoDB está utilizando índice único en múltiples columna de la siguiente manera:

Tabla 'Sesiones' { unique_key (browser_session_id, profile_id) // asegura que la inserción de 1 entrada por sesión se producirá una vez }

select count (browser_session_id) de Sesiones

garantizará r Esult de sesiones únicas, ya que no se permiten varias sesiones por usuario.

Conclusiones

  • Advantage

    Cada inserto requiere una pre-selección.

  • Desventaja

    no es adecuado para todos los casos.

    puede ralentizar el rendimiento de escritura, y requiere un manejo adicional