El concepto de multi-versionado (MVCC, Control de Concurrencia de Múltiples Versiones) surgió como una alternativa a los bloqueos estrictos, para permitir la operación paralela de un gran número de transacciones. Esto era importante para reducir conflictos y bloqueos al acceder a los datos simultáneamente, lo que es especialmente crítico en sistemas OLTP.
Los enfoques tradicionales de bloqueo (por ejemplo, bloqueo a nivel de fila) pueden llevar a ralentizaciones de las aplicaciones en caso de alta competencia. La tarea de MVCC es permitir que las transacciones lean instantáneas consistentes de los datos, incluso si hay operaciones de escritura en paralelo, asegurando así el aislamiento y el acceso simultáneo.
MVCC se implementa en bases de datos populares (PostgreSQL, Oracle, MySQL/InnoDB) mediante el almacenamiento de historiales de versiones de filas. Al leer, cada transacción solo ve las filas que se habían confirmado antes de su inicio, mientras que las inserciones/actualizaciones crean nuevas versiones de las filas sin eliminarlas de inmediato.
Ejemplo de consulta (PostgreSQL):
BEGIN TRANSACTION; SELECT * FROM orders WHERE status = 'processing'; UPDATE orders SET status = 'completed' WHERE id = 42; COMMIT;
Mientras la transacción no esté completada, los demás usuarios verán la versión anterior de la fila, y solo después de confirmar los cambios serán accesibles para nuevas transacciones.
Características clave:
¿Puede MVCC eliminar completamente todos los tipos de bloqueos y conflictos?
No, en MVCC aún pueden ocurrir conflictos durante las actualizaciones simultáneas de las mismas filas; por ejemplo, en actualizaciones simultáneas surge un conflicto de confirmaciones (conflicto de escritura), y la base de datos lanza un error o revierte una de las transacciones.
¿Cuándo se eliminan las viejas versiones de filas en MVCC y puede esto llevar a fugas de memoria?
En la mayoría de las bases de datos, las viejas versiones de filas se eliminan mediante procesos especiales (VACUUM en PostgreSQL). Si estos procesos no se ejecutan, la base se "expande" y el rendimiento disminuye.
¿Funcionan correctamente los "select for update" en condiciones de MVCC, y por qué es necesario el bloqueo?
Sí, las consultas SELECT FOR UPDATE bloquean filas para evitar conflictos en cambios paralelos; de lo contrario, podrían ocurrir "actualizaciones perdidas".
Ejemplo:
BEGIN; SELECT * FROM products WHERE id = 123 FOR UPDATE; UPDATE products SET quantity = quantity - 1 WHERE id = 123; COMMIT;
En una gran tienda en línea, se implementó un esquema con frecuentes actualizaciones de pedidos sin configurar VACUUM. Después de un mes, la base creció 10 veces, y las consultas se ralentizaron notablemente.
Pros:
Contras:
Se implementó un autovacuum regular, se utilizó control de conflictos de escritura y aislamiento a nivel de LECTURA REPETIBLE solo para consultas críticas.
Pros:
Contras: