¿Dónde almacena InnoDB datos de transacciones antes de confirmarlos?

12

He hecho algunas pruebas usando READ_COMMITTEDy READ_UNCOMMITTEDen casa, usando la tecnología JDBC.

Veo que en READ_UNCOMMITTEDrealidad puede leer datos no confirmados, por ejemplo, datos de alguna transacción aún no confirmada (podría realizar una consulta UPDATE).

Preguntas

  • ¿Dónde se almacenan los datos no confirmados, de modo que una READ_UNCOMMITTEDtransacción pueda leer datos no confirmados de otra transacción?
  • ¿Por qué no es posible que una READ_COMMITTEDtransacción lea datos no confirmados, es decir, realizar una "lectura sucia"? ¿Qué mecanismo hace cumplir esta restricción?
Shuzheng
fuente

Respuestas:

11

" ¿Dónde se almacenan los datos no confirmados, de modo que una transacción READ_UNCOMMITTED pueda leer datos no confirmados de otra transacción? "

Las nuevas versiones de registro no confirmado (PK agrupado) se tratan como la versión "actual" del registro en la página. Por lo tanto, se pueden almacenar en el grupo de búferes y / o en el espacio de tabla (por ejemplo, tablename.ibd). Las transacciones que luego necesitan construir una instantánea / vista en algo que no sea READ-UNCOMMITTED, necesitan construir una versión anterior de la fila (siguiendo la lista del historial) usando los registros UNDO (almacenados en el espacio de tabla del sistema ). Al leer el registro no confirmado, es posible que InnoDB también necesite leer algunos registros de índice secundario no confirmados del Change Buffer y aplicarlos antes de presentar el registro nuevamente al usuario.

Es este comportamiento el que puede hacer que las reversiones en InnoDB sean relativamente caras. Es el gran factor que también puede conducir a posibles problemas de rendimiento de transacciones inactivas de larga duración que tienen registros actualizados, ya que esas transacciones bloquearán las operaciones de purga y la lista de historial de versiones de registros antiguas aumenta, y los registros UNDO necesarios para reconstruir esas versiones antiguas a pedido, continuará creciendo. Ralentiza las nuevas transacciones que necesitan leer una versión anterior / comprometida del registro, ya que necesitan recorrer una lista de historial cada vez más larga, que es una lista individualmente vinculada de registros UNDO, y hacer más trabajo para reconstruir La versión anterior del registro. Entonces terminas usando muchos ciclos de CPU (sin mencionar las primitivas de bloqueo interno: mutexes, rw_locks, semáforos, etc.

Con suerte eso tiene sentido? :)

Como FYI, en MySQL 5.7 puede mover el espacio de tabla UNDO y los registros fuera del espacio de tabla del sistema , y hacerlos truncar automáticamente. Pueden crecer bastante si tiene una transacción de larga duración que impide las operaciones de purga, lo que resulta en una longitud de lista de historial muy larga y cada vez mayor. Tenerlos almacenados en el espacio de tabla del sistema fue la causa más común de un archivo ibdata1 enorme / en crecimiento, que a su vez no se puede truncar / encoger / aspirar para reclamar más tarde ese espacio.

Matt Lord
fuente
4

Tu preguntaste

¿Dónde se almacenan los datos no confirmados, de modo que una transacción READ_UNCOMMITTED puede leer datos no confirmados de otra transacción?

Para responder a su pregunta, necesita saber cómo es la Arquitectura InnoDB.

La siguiente imagen fue creada hace años por el CTO de Percona Vadim Tkachenko

Arquitectura InnoDB

De acuerdo con la documentación de MySQL sobre el modelo de transacción InnoDB y el bloqueo

Un COMPROMISO significa que los cambios realizados en la transacción actual se hacen permanentes y se hacen visibles para otras sesiones. Una declaración ROLLBACK, por otro lado, cancela todas las modificaciones realizadas por la transacción actual. Tanto COMMIT como ROLLBACK liberan todos los bloqueos de InnoDB que se establecieron durante la transacción actual.

Dado que COMMIT y ROLLBACK gobiernan la visibilidad de los datos, READ COMMITTED y READ UNCOMMITTED tendrían que depender de estructuras y mecanismos que registren los cambios.

  1. Rollback Segments / Undo Space
  2. Rehacer registros
  3. Brechas Cerraduras contra la (s) mesa (s) involucradas

Los segmentos de reversión y el espacio de deshacer sabrían cómo se veían los datos modificados antes de aplicarlos. Rehacer registros sabría qué cambios se deben avanzar para que los datos aparezcan actualizados.

También preguntaste

¿Por qué no es posible que una transacción READ_COMMITTED lea datos no confirmados, es decir, realizar una "lectura sucia"? ¿Qué mecanismo hace cumplir esta restricción?

Redo Logs, Undo Space y Filas bloqueadas entran en juego. También debe considerar el InnoDB Buffer Pool (donde puede medir páginas sucias con innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty e innodb_buffer_pool_bytes_dirty ).

A la luz de esto, READ COMMITTED sabría cómo aparecen los datos de forma permanente. Por lo tanto, no es necesario buscar páginas sucias que no se hayan confirmado. LEER COMPROMETIDO no sería más que una lectura sucia que se ha cometido. READ UNCOMMITTED habría seguido sabiendo qué filas se deben bloquear y qué registros de rehacer se han leído o ignorado para que los datos sean visibles.

Para comprender completamente el bloqueo de filas para gestionar el aislamiento, lea El modelo de transacción y bloqueo de InnoDB

RolandoMySQLDBA
fuente
1
Primero, gracias por su respuesta y modificación de mi publicación ... Entonces, antes de un COMPROMISO, ¿los cambios no son visibles para otros usuarios del sistema? Aquí el usuario literalmente significa una transacción, ¿verdad? Dado que READ UNCOMMITTED puede leer datos no confirmados, ¿dónde lee este nivel de aislamiento estos datos? ¿Podría haber más de una fuente de datos no confirmados para un elemento de datos en particular en una base de datos? De ser así, ¿qué datos no confirmados se leerán?
Shuzheng