El control de concurrencia multiversión ( MCC o MVCC ) es un método de control de concurrencia sin bloqueo comúnmente utilizado por los sistemas de gestión de bases de datos para proporcionar acceso concurrente a la base de datos y en lenguajes de programación para implementar memoria transaccional . [1]
Sin control de concurrencia, si alguien está leyendo de una base de datos al mismo tiempo que otra persona está escribiendo en ella, es posible que el lector vea un fragmento de datos a medio escribir o inconsistente . Por ejemplo, al realizar una transferencia bancaria entre dos cuentas bancarias, si un lector lee el saldo en el banco cuando el dinero se ha retirado de la cuenta original y antes de que se haya depositado en la cuenta de destino, parecería que el dinero ha desaparecido del banco. El aislamiento es la propiedad que proporciona garantías en los accesos concurrentes a los datos. El aislamiento se implementa mediante un protocolo de control de concurrencia . La forma más sencilla es hacer que todos los lectores esperen hasta que el escritor termine, lo que se conoce como bloqueo de lectura-escritura . Se sabe que los bloqueos crean contención, especialmente entre transacciones de lectura largas y transacciones de actualización. MVCC tiene como objetivo resolver el problema manteniendo múltiples copias de cada elemento de datos. De esta manera, cada usuario conectado a la base de datos ve una instantánea de la base de datos en un instante particular en el tiempo. Cualquier cambio realizado por un escritor no será visto por otros usuarios de la base de datos hasta que los cambios se hayan completado (o, en términos de base de datos: hasta que se haya confirmado la transacción ).
Cuando una base de datos MVCC necesita actualizar un dato, no sobrescribirá el elemento de datos original con datos nuevos, sino que creará una versión más nueva del elemento de datos. Por lo tanto, se almacenan varias versiones. La versión que ve cada transacción depende del nivel de aislamiento implementado. El nivel de aislamiento más común implementado con MVCC es el aislamiento de instantáneas . Con el aislamiento de instantáneas, una transacción observa un estado de los datos en el momento en que se inició la transacción.
MVCC proporciona vistas consistentes en un momento determinado . Las transacciones de lectura bajo MVCC generalmente usan una marca de tiempo o un ID de transacción para determinar qué estado de la base de datos leer y leer estas versiones de los datos. De esta manera, las transacciones de lectura y escritura quedan aisladas entre sí sin necesidad de bloqueos. Sin embargo, a pesar de que los bloqueos son innecesarios, algunas bases de datos MVCC, como Oracle, los usan. Las escrituras crean una versión más nueva, mientras que las lecturas simultáneas acceden a una versión anterior.
MVCC presenta el desafío de cómo eliminar versiones que se vuelven obsoletas y nunca se leerán. En algunos casos, se implementa un proceso para barrer y eliminar periódicamente las versiones obsoletas. Este suele ser un proceso de detención del mundo que recorre una tabla completa y la reescribe con la última versión de cada elemento de datos. PostgreSQL puede utilizar este enfoque con su proceso VACUUM FREEZE. Otras bases de datos dividen los bloques de almacenamiento en dos partes: la parte de datos y un registro de deshacer. La parte de datos siempre conserva la última versión confirmada. El registro de deshacer permite la recreación de versiones anteriores de los datos. La principal limitación inherente de este último enfoque es que cuando hay cargas de trabajo intensivas en actualizaciones, la parte del registro de deshacer se queda sin espacio y luego las transacciones se cancelan porque no se les puede dar su instantánea. Para una base de datos orientada a documentos, también permite que el sistema optimice los documentos escribiendo documentos completos en secciones contiguas del disco: cuando se actualiza, se puede reescribir todo el documento en lugar de cortar fragmentos o mantenerlos en una estructura de base de datos vinculada y no contigua.
MVCC utiliza marcas de tiempo ( TS ) e identificaciones de transacciones crecientes para lograr la consistencia transaccional . MVCC garantiza que una transacción ( T ) nunca tenga que esperar para leer un objeto de base de datos ( P ) al mantener varias versiones del objeto. Cada versión del objeto P tiene una marca de tiempo de lectura ( RTS ) y una marca de tiempo de escritura ( WTS ) que permite que una transacción particular T i lea la versión más reciente del objeto que precede a la marca de tiempo de lectura RTS ( T i ) de la transacción.
Si la transacción T i desea escribir en el objeto P y también hay otra transacción T k que se está realizando en el mismo objeto, la marca de tiempo de lectura RTS ( T i ) debe preceder a la marca de tiempo de lectura RTS ( T k ), es decir, RTS ( T i ) < RTS ( T k ) [ aclaración necesaria ] , para que la operación de escritura del objeto ( WTS ) tenga éxito. Una escritura no se puede completar si hay otras transacciones pendientes con una marca de tiempo de lectura ( RTS ) anterior en el mismo objeto. Al igual que cuando hace cola en la tienda, no puede completar su transacción de pago hasta que los que están delante de usted hayan completado la suya.
Para reformular; cada objeto ( P ) tiene una marca de tiempo ( TS ); sin embargo, si la transacción T i desea escribir en un objeto y la transacción tiene una marca de tiempo ( TS ) que es anterior a la marca de tiempo de lectura actual del objeto, TS ( T i ) < RTS ( P ), entonces la transacción se cancela y se reinicia. (Esto se debe a que una transacción posterior ya depende del valor anterior). De lo contrario, T i crea una nueva versión del objeto P y establece la marca de tiempo de lectura/escritura TS de la nueva versión en la marca de tiempo de la transacción TS ← TS ( T i ). [2]
La desventaja de este sistema es el costo de almacenar múltiples versiones de objetos en la base de datos. Por otro lado, las lecturas nunca se bloquean, lo que puede ser importante para cargas de trabajo que involucran principalmente la lectura de valores de la base de datos. MVCC es particularmente hábil para implementar un verdadero aislamiento de instantáneas , algo que otros métodos de control de concurrencia con frecuencia hacen de manera incompleta o con altos costos de rendimiento.
En el tiempo = 1, el estado de una base de datos podría ser:
T0 escribió Object 1="Foo" y Object 2="Bar". Después de eso, T1 escribió Object 1="Hello" y dejó Object 2 con su valor original. El nuevo valor de Object 1 reemplazará al valor 0 para todas las transacciones que comiencen después de que T1 realice la confirmación, momento en el que la versión 0 de Object 1 puede ser recolectada como basura.
Si una transacción de ejecución prolongada T2 inicia una operación de lectura del Objeto 2 y el Objeto 1 después de que se confirma T1 y hay una transacción de actualización simultánea T3 que elimina el Objeto 2 y agrega el Objeto 3="Foo-Bar", el estado de la base de datos se verá así en el momento 2:
Hay una nueva versión a partir del momento 2 del Objeto 2 que está marcado como eliminado y un nuevo Objeto 3. Dado que T2 y T3 se ejecutan simultáneamente, T2 ve la versión de la base de datos anterior a 2, es decir, anterior a que T3 confirmara las escrituras, por lo que T2 lee el Objeto 2="Bar" y el Objeto 1="Hello". Así es como el control de concurrencia de múltiples versiones permite lecturas de aislamiento de instantáneas sin ningún bloqueo.
El control de concurrencia multiversión se describe con cierto detalle en el artículo de 1981 "Control de concurrencia en sistemas de bases de datos distribuidas" [3] de Phil Bernstein y Nathan Goodman, que en ese entonces trabajaban para la Computer Corporation of America . El artículo de Bernstein y Goodman cita una disertación de 1978 [4] de David P. Reed que describe claramente el MVCC y lo reivindica como un trabajo original.
El primer software de base de datos comercial que se lanzó al mercado con MVCC fue VAX Rdb/ELN , lanzado en 1984 [5] y creado en Digital Equipment Corporation por Jim Starkey . Starkey luego [6] creó la segunda base de datos MVCC comercialmente exitosa: InterBase [7] .