2009-05-27 23 views
107

Consulta:¿Alguna manera de seleccionar sin causar bloqueo en MySQL?

SELECT COUNT(online.account_id) cnt from online; 

Pero mesa en línea también se modifica por un evento, por lo que con frecuencia se puede ver que la cerradura mediante la ejecución de show processlist.

¿Hay alguna gramática en MySQL que pueda hacer que la instrucción select no cause bloqueos?

Y he olvidado mencionar que está en una base de datos esclava MySQL.

Después añadí en my.cnf:transaction-isolation = READ-UNCOMMITTED el esclavo se reunirá con el error:

Error 'Binary logging not possible. Message: Transaction level 'READ-UNCOMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'' on query 

Por lo tanto, hay una manera compatible para hacer esto?

+2

Para otros que se encuentran con esta pregunta y están teniendo problemas con los bloqueos en sus tablas: Cómo MySQL utiliza bloqueos internamente depende del motor de almacenamiento. Lea la respuesta de @zombat a continuación. –

Respuesta

11

Es posible que desee leer this page del manual de MySQL. La forma en que se bloquea una tabla depende del tipo de tabla que sea.

MyISAM utiliza bloqueos de tabla para lograr una velocidad de lectura muy alta, pero si tiene una instrucción UPDATE en espera, los SELECTS futuros se pondrán en cola detrás de la ACTUALIZACIÓN.

Las tablas InnoDB usan el bloqueo de nivel de fila, y no tendrá toda la tabla bloqueada detrás de una ACTUALIZACIÓN. Hay otro tipo de problemas de bloqueo asociados con InnoDB, pero es posible que encuentre que se ajusta a sus necesidades.

+1

¿Funcionará "AJUSTE DE NIVEL DE AISLAMIENTO DE TRANSACCIÓN LEÍDO" para las tablas MyISAM? – omg

+5

Las tablas MyISAM no admiten transacciones de ninguna forma. Una consulta transaccional se ejecutará en una tabla MyISAM, por lo que la consulta que mencione anteriormente se ejecutará, pero no tendrá ningún efecto. – zombat

+1

Entonces, ¿qué puedo hacer para evitar SELECCIONES haciendo cola en el caso de MyISAM? – omg

0

De this referencia:

If you acquire a table lock explicitly with LOCK TABLES, you can request a READ LOCAL lock rather than a READ lock to enable other sessions to perform concurrent inserts while you have the table locked.

19

Si la tabla es InnoDB, consulte http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - que utiliza (modo no-bloqueo)-leer consistente para SELECTs "que no se especifica FOR UPDATE o LOCK IN SHARE MODE si se establece la opción innodb_locks_unsafe_for_binlog y el nivel de aislamiento de la transacción no se establece en SERIALIZABLE. Por lo tanto, no se establecen bloqueos en las filas leídas desde la tabla seleccionada ".

13

Uso

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

Version 5.0 Docs son here.

Versión 5.1 Los documentos son here.

+2

Gracias, creo que está cerca, pero ¿cuánto tiempo va a afectar esta afirmación? Voy a utilizar esta declaración en un programa PHP, y debería ser el mejor resetear el NIVEL DE AISLAMIENTO DE LA TRANSACCIÓN automáticamente una vez que la consulta finalizó – omg

2

Dependiendo de su tipo de tabla, el bloqueo funcionará de manera diferente, pero también lo hará un conteo SELECT. Para las tablas MyISAM, una simple tabla SELECT count (*) FROM no debe bloquear la tabla, ya que accede a metadatos para extraer el recuento de registros. Innodb tomará más tiempo ya que tiene que tomar la mesa en una instantánea para contar los registros, pero no debe causar bloqueo.

Al menos debe haber configurado concurrent_insert en 1 (valor predeterminado). Luego, si no hay "lagunas" en el archivo de datos para que la tabla se llene, las inserciones se agregarán al archivo y SELECCIONAR e INSERTAR pueden ocurrir simultáneamente con las tablas MyISAM. Tenga en cuenta que eliminar un registro pone un "espacio" en el archivo de datos que intentará llenarse con inserciones y actualizaciones futuras.

Si rara vez borra registros, puede establecer concurrent_insert igual a 2 y las inserciones siempre se agregarán al final del archivo de datos. Luego, las selecciones y las inserciones pueden realizarse simultáneamente, pero su archivo de datos nunca se volverá más pequeño, sin importar cuántos registros elimine (excepto todos los registros).

La línea de fondo, si tiene muchas actualizaciones, inserta y selecciona en una tabla, debe hacerlo InnoDB. Sin embargo, puedes mezclar libremente tipos de tabla en un sistema.

130

encontrado un artículo titulado "MySQL con NOLOCK"

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

en MSSQL que hacer lo siguiente:

SELECT * FROM TABLE_NAME WITH (nolock) 

y el equivalente MySQL es

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; 
SELECT * FROM TABLE_NAME ; 
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ; 

EDITAR

Michael Mior sugirió los siguientes (a partir de los comentarios)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; 
SELECT * FROM TABLE_NAME ; 
COMMIT ; 
+6

Gracias, entonces esto funcionará para Innodb, pero ¿y si MyISAM? – omg

+41

Solo una nota para futuros lectores en la que quizás desee eliminar 'SESSION' y, por lo tanto, hacer que el nivel de transacción se aplique solo a la próxima transacción. Entonces, simplemente reemplaza la tercera declaración anterior con 'COMMIT'. Esto será un noop en este caso, pero tendrá un efecto secundario al finalizar la transacción y restablecer el nivel de aislamiento predeterminado. –

+3

Solo una nota, ese enlace está muerto ... :( – longda

1

SELECTs normalmente no hacen ningún bloqueo que se preocupa de las tablas InnoDB. El nivel de aislamiento de transacción predeterminado significa que las selecciones no bloquean cosas.

Por supuesto, la disputa todavía ocurre.

+0

Sé que esta publicación es antigua, pero esta respuesta es demasiado general y solo a veces es cierta. Ver http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html. Las cerraduras ciertamente son adquiridas para lecturas, dependiendo del nivel de aislamiento. Específicamente, en este caso, el póster trata con bases de datos replicadas y afirma explícitamente que puede usar 'show processlist' para ver realmente los bloqueos. Por lo tanto, es seguro asumir que, de hecho, se están tomando bloqueos. – Craig

+1

La respuesta es siempre cierta. Por supuesto, hay algunos bloqueos, algunos mutexes internos dentro de innodb que se usan (innolb buffer mutex, por ejemplo). La mayoría de los usuarios no se preocupan por estos bloqueos ni se fijan en ellos, y normalmente solo disputaban durante las operaciones DDL (como, por ejemplo, si tienes un grupo de búferes 16G y haces "drop table" en otro hilo). Pero no requiere ningún bloqueo de fila por defecto. A eso me refería. La respuesta fue bastante vaga. – MarkR

+1

_Siempre_ siempre? ¿Qué pasa si el nivel de aislamiento de la transacción se establece en serializable, o la declaración de selección utiliza LOCK IN SHARE MODE y la confirmación automática está deshabilitada? Sé que muchos (¿la mayoría/todos?) Los servidores de bases de datos ahora usan el aislamiento de instantáneas de forma predeterminada en lugar de la verdadera serialización, pero ¿todavía no hay justificaciones ocasionales para forzar lecturas serializables? Pero parece que dijiste que en todos los casos remotamente normales, las condiciones predeterminadas en MySQL no causan bloqueos de lectura que afecten a otros hilos, así que no te preocupes por un problema que no tienes. Traté de deshacer mi voto negativo, por cierto. Lo siento ... – Craig

0

Otra forma de habilitar la lectura sucia en mysql es agregar pista: BLOQUEO EN EL MODO COMPARTIR SELECCIONAR * DESDE TABLE_NAME BLOQUEAR EN MODO COMPARTIR;