MySQL Optimization Lección 6: Comprensión profunda del nivel de aislamiento de transacciones de Mysql y el mecanismo de bloqueo

Visión de conjunto

Nuestra base de datos generalmente ejecuta varias transacciones al mismo tiempo, y varias transacciones pueden agregar, eliminar, modificar y consultar el mismo lote de datos al mismo tiempo, lo que puede conducir a lo que llamamos escrituras sucias, lecturas sucias, lecturas no repetibles y lecturas fantasma. . La esencia de estos problemas es el problema de concurrencia de transacciones múltiples de la base de datos.Para resolver el problema de concurrencia de transacciones múltiples, la base de datos está diseñada 事务隔离机制、锁机制、MVCC多版本并发控制隔离机制con un conjunto de mecanismos 解决多事务并发问题.

Transacciones y sus propiedades ACID

Una transacción es una unidad de procesamiento lógico compuesta por un conjunto de sentencias SQL.Una transacción tiene los siguientes cuatro atributos, que generalmente se conocen como el atributo ACID de la transacción.

  • Atomicidad: una transacción es una unidad atómica de operación en la que se realizan todos o ninguno de los cambios en los datos.
  • Coherente: los datos deben permanecer en un estado coherente tanto al comienzo como al finalizar una transacción. Esto significa que se deben aplicar todas las reglas de datos relevantes a la modificación de la transacción para mantener la integridad de los datos.
  • Aislamiento: el sistema de base de datos proporciona cierto mecanismo de aislamiento para garantizar que las transacciones se ejecuten en un entorno independiente que no se vea afectado por operaciones concurrentes externas. Esto significa que el estado intermedio en el proceso de transacción es invisible para el mundo exterior y viceversa.
  • Duradero: una vez completada la transacción, sus modificaciones a los datos son permanentes y se pueden mantener incluso en caso de falla del sistema.

Problemas con el procesamiento de transacciones concurrentes

Actualización perdida o escritura sucia

El problema de actualización perdida ocurre cuando dos o más transacciones seleccionan la misma fila y luego actualizan esa fila en función del valor seleccionado originalmente, ya que cada transacción desconoce la existencia de la otra transacción: la última actualización sobrescribe el valor creado por la otra transacción . hizo actualizaciones .

Lecturas sucias

Una transacción está modificando un registro. Antes de que la transacción se complete y confirme, los datos de este registro están en un estado inconsistente; en este momento, otra transacción también lee el mismo registro. Si no se controla, la segunda Transacción que lee este datos "sucios" y realizar un procesamiento posterior basado en ellos para crear dependencias de datos no comprometidas. Este fenómeno se llama vívidamente " 脏读".

En una frase:La transacción A lee los datos que la transacción B ha modificado pero aún no ha confirmado, y también hacer operaciones sobre esta base de datos. En este punto, si la transacción B retrocede, los datos leídos por A no son válidos y no cumplen con los requisitos de consistencia.

Lecturas no repetibles

En un momento determinado, después de que una transacción lee algunos datos, vuelve a leer los datos leídos anteriormente, pero descubre que los datos que ha leído han cambiado o que se han eliminado algunos registros. Este fenómeno se llama " 不可重复读".
En una frase:La misma declaración de consulta dentro de la transacción A lee resultados inconsistentes en diferentes momentos, lo que no se ajusta al aislamiento.

Lecturas fantasma

Una transacción vuelve a leer los datos recuperados previamente de acuerdo con las mismas condiciones de consulta, pero descubre que otras transacciones han insertado nuevos datos que satisfacen sus condiciones de consulta. Este fenómeno se denomina " 幻读".

Nivel de aislamiento de transacciones

Las "lecturas sucias", las "lecturas no repetibles" y las "lecturas fantasma" son 数据库读一致性问题resueltas por la base de datos que proporciona un determinado mecanismo de aislamiento de transacciones.
inserte la descripción de la imagen aquí
Cuanto más estricto sea el aislamiento de transacciones de la base de datos, menores serán los efectos secundarios concurrentes, pero mayor será el costo, porque el aislamiento de transacciones consiste esencialmente en hacer que la transacción se "serialice" hasta cierto punto, lo que obviamente es contradictorio con la "concurrencia".
Al mismo tiempo, diferentes aplicaciones tienen diferentes requisitos para la coherencia de lectura y el aislamiento de transacciones. Por ejemplo, muchas aplicaciones no son sensibles a la "lectura no repetible" y la "lectura fantasma", y pueden estar más preocupadas por la capacidad de acceder a los datos simultáneamente. .

-- 看当前数据库的事务隔离级别
show variables like 'tx_isolation'; -- mysql8.0之前的写法
show variables like 'transaction_isolation'; -- mysql8.0的写法

-- 设置事务隔离级别
set tx_isolation='REPEATABLE-READ';-- mysql8.0之前的写法
set transaction_isolation='REPEATABLE-READ';-- mysql8.0的写法

El nivel de aislamiento de transacción predeterminado de Mysql es lectura repetible. Al desarrollar programas con Spring, si no se establece el nivel de aislamiento, se usa el nivel de aislamiento establecido por Mysql de manera predeterminada. Si se establece Spring, se usa el nivel de aislamiento que se ha establecido. .

mecanismo de bloqueo

Un bloqueo es un mecanismo mediante el cual una computadora coordina el acceso simultáneo a un recurso por parte de múltiples procesos o subprocesos.
En la base de datos, además de la contención de los recursos informáticos tradicionales (como CPU, RAM, E/S, etc.), los datos también son un recurso que los usuarios deben compartir.
Cómo garantizar la coherencia y la validez del acceso simultáneo a los datos es un problema que todas las bases de datos deben resolver, y el conflicto de bloqueo también es un factor importante que afecta el rendimiento del acceso simultáneo a la base de datos.

clasificación de bloqueo

  • DesdeactuaciónLo anterior se divide en: 乐观锁(implementado por comparación de versiones) y悲观锁

  • DesdeTipos de operaciones en la base de datos.Dividido en: 读锁y 写锁(ambos son bloqueos pesimistas)
    读锁(共享锁,S锁(Shared)): para los mismos datos, se pueden realizar múltiples operaciones de lectura simultáneamente sin afectarse entre sí
    写锁(排它锁,X锁(eXclusive)): antes de que se complete la operación de escritura actual, bloqueará otros bloqueos de escritura y bloqueos de lectura y
    bloqueará los bloqueos de lectura Escribe, pero no bloquea las lecturas. El bloqueo de escritura bloquea tanto la lectura como la escritura.

  • A partir de la granularidad de las operaciones de datos, se divide en: bloqueos de tabla y bloqueos de fila

bloqueo de mesa

Cada operación bloquea toda la tabla. Baja sobrecarga y bloqueo rápido; sin punto muerto; gran granularidad de bloqueo, la mayor probabilidad de conflicto de bloqueo y la menor concurrencia; generalmente se usa en el escenario de migración de datos de tabla completa.

Operación básica

#建表SQL(MyISAM存储引擎)
CREATE TABLE `mylock` (
  `id` INT (11) NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR (20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8;

#插入数据
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('1', 'a');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('2', 'b');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('3', 'c');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('4', 'd');
-- 手动增加表锁:
lock table 表名称 read(write), 表名称2 read(write)-- 查看表上加过的锁:
show open tables;
-- 删除表锁:
unlock tables; 

bloqueo de fila

Cada operación bloquea una fila de datos. Alta sobrecarga y bloqueo lento; ocurrirán interbloqueos; la granularidad de bloqueo es la más pequeña, la probabilidad de conflictos de bloqueo es la más baja y la concurrencia es la más alta.

InnoDBMYISAMHay dos grandes diferencias con :

  • Transacciones de soporte (TRANSACCIÓN)
  • Bloqueo de nivel de fila de soporte

demostración de bloqueo de fila

Una sesión abre actualizaciones de transacciones sin comprometerse, otra sesión bloqueará la actualización del mismo registro y la actualización de diferentes registros no bloqueará

Resumir

Antes de ejecutar la instrucción de consulta SELECT, MyISAM agregará automáticamente bloqueos de lectura a todas las tablas involucradas y agregará automáticamente bloqueos de escritura a las tablas involucradas al ejecutar operaciones de actualización, inserción y eliminación.

Cuando InnoDB ejecuta la declaración de consulta SELECT, no se bloqueará debido al mecanismo mvcc, pero las operaciones de actualización, inserción y eliminación agregarán bloqueos de fila

En resumen, lo es 读锁会阻塞写,但是不会阻塞读。而写机制会把读和写都阻塞.

Análisis de casos de niveles de bloqueo y aislamiento de filas

CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `account` (`name`, `balance`) VALUES ('lilei', '450');
INSERT INTO `account` (`name`, `balance`) VALUES ('hanmei','16000');
INSERT INTO `account` (`name`, `balance`) VALUES ('lucy', '2400');

leer sin compromiso

1. Abra un cliente A y configure el nivel de aislamiento de transacción actual para leer sin confirmar (leer sin confirmar)

set tx_isolation='read-uncommitted';
set transaction_isolation = 'read-uncommitted'; -- mysql8.0

Consultar el valor inicial de la cuenta de la tabla:
inserte la descripción de la imagen aquí
2. Antes de que se confirme la transacción del cliente A, abra otro cliente B y actualice la cuenta de la tabla
inserte la descripción de la imagen aquí
3. En este momento, aunque la transacción del cliente B no se ha comprometido, el cliente A puede consultar A los datos que ha actualizado B
inserte la descripción de la imagen aquí
4. Una vez que la transacción del cliente B se revierte por algún motivo, todas las operaciones se desharán y los datos consultados por el cliente A son realmente datos sucios
inserte la descripción de la imagen aquí
5. Ejecute la declaración de actualización en el cliente A actualizar cuenta establecer saldo = saldo - 50 donde id = 1,
el saldo de lilei no se convirtió en 350, sino en 400. ¿No es extraño que los datos sean inconsistentes ?如果你这样想就太天真了,在应用程序中,我们会用400-50 = 350,并不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离机制
inserte la descripción de la imagen aquí

leer comprometido

1. Abra un cliente A, configure el nivel de aislamiento de transacciones actual para lectura confirmada (lectura no confirmada) y consulte todos los registros en la cuenta de la tabla

set transaction_isolation = 'read-committed'; -- mysql8.0

inserte la descripción de la imagen aquí

2. Antes de confirmar la transacción del cliente A, abra otro cliente B y actualice la cuenta de la tabla
inserte la descripción de la imagen aquí
3. En este momento, la transacción del cliente B no se ha confirmado y el cliente A no puede consultar los datos que ha actualizado B. 解决了脏读问题
inserte la descripción de la imagen aquí
4. El cliente Se envía la transacción del terminal B
inserte la descripción de la imagen aquí
5. El cliente A ejecuta la misma consulta que el paso anterior, y el resultado es inconsistente con el paso anterior, es decir, se produce un problema de lectura no repetible
inserte la descripción de la imagen aquí

lectura repetible

1. Abra un cliente A, establezca el modo de transacción actual en lectura repetible y consulte todos los registros en la cuenta de la tabla

set transaction_isolation = 'repeatable-read';

inserte la descripción de la imagen aquí
2. Antes de confirmar la transacción del cliente A, abra otro cliente B, actualice la cuenta de la tabla y envíela
inserte la descripción de la imagen aquí
3. Consulte todos los registros en la cuenta de la tabla del cliente A, el resultado de la consulta es consistente con el paso 1. No hay Pregunta de lectura repetible
inserte la descripción de la imagen aquí
4. En el cliente A, ejecute la actualización de la cuenta establecida saldo = saldo - 50 donde id = 1,
el saldo no se convierte en 350-50 = 300, el valor del saldo de lilei se calcula usando 300 en el paso 2, por lo que es 250 , y la consistencia de los datos no se destruye.

El mecanismo MVCC (control de concurrencia de múltiples versiones) se utiliza bajo el nivel de aislamiento de lectura repetible. La operación de selección no actualizará el número de versión, pero es una lectura instantánea (versión histórica); insertar, actualizar y eliminar actualizará el número de versión , que es la lectura actual (versión actual). )
inserte la descripción de la imagen aquí
5. Vuelva a abrir el cliente B, inserte un nuevo dato y envíelo
inserte la descripción de la imagen aquí
6. Consulte todos los registros en la tabla de cuentas del cliente A y no se encuentran nuevos datos, por lo que no se produce ninguna lectura fantasma
inserte la descripción de la imagen aquí
7. Verifique la lectura fantasma
y Ejecute la cuenta de actualización en el cliente A. Establezca el saldo = 888 donde id = 4.
Se puede actualizar con éxito y los nuevos datos del cliente B se pueden encontrar consultando nuevamente
inserte la descripción de la imagen aquí

publicar por fascículos

1. Abra un cliente A, establezca el modo de transacción actual en serializable y consulte el valor inicial de la cuenta de la tabla

set transaction_isolation = 'serializable';

inserte la descripción de la imagen aquí

2. Abra un cliente B y configure el modo de transacción actual en serializable. La actualización del mismo registro con id 1 se bloqueará y esperará, y la actualización del registro con id 2 puede ser exitosa, lo que indica que las consultas de InnoDB en modo serie también se bloquearán. Bloqueo de fila más
Si el cliente A ejecuta una consulta de rango, todas las filas del rango incluyen el rango de intervalo de brecha donde se encuentra cada fila de registros (incluso si los datos de la fila no se han insertado, se bloquearán, que es la brecha bloqueo) está bloqueado .
En este momento, si el cliente B inserta datos en este rango, se bloqueará, por lo que se evita la lectura fantasma.
这种隔离级别并发度极低,开发中很少会用到
inserte la descripción de la imagen aquí

Bloqueo de espacio

Un bloqueo de espacio bloquea el espacio entre dos valores. El nivel predeterminado de Mysql es de lectura repetible.¿Hay alguna forma de resolver el problema de lectura fantasma? Los bloqueos de espacios pueden resolver lecturas fantasma en algunos casos.

Ajuste el nivel de aislamiento al nivel de aislamiento predeterminado de mysql, y la cuenta tiene los siguientes datos:
inserte la descripción de la imagen aquí
luego la brecha tiene ids (3,10), (10,20), (20, infinito positivo) Estos tres intervalos
se ejecutan bajo el cliente Un nombre de conjunto de cuentas de actualización = 'zhuge' donde id > 8 e id < 18;
luego, otros clientes no pueden insertar ni modificar ningún dato en todos los registros de fila incluidos en este rango y la brecha entre los registros de fila , es decir, la identificación está en ( 3,20] el intervalo no puede modificar los datos, tenga en cuenta que también se incluyen los últimos 20
间隙锁是在可重复读隔离级别下才会生效.

Bloqueos de tecla siguiente

Los bloqueos de tecla siguiente son una combinación de bloqueos de fila y bloqueos de espacio. El intervalo completo de (3,20] en el ejemplo anterior se puede llamar un bloqueo de teclas

Los bloqueos de fila sin índice se actualizan a bloqueos de tabla

El bloqueo se agrega principalmente al índice. Si se actualiza el campo que no es de índice, el bloqueo de fila puede convertirse en un bloqueo de tabla.

  • El cliente A ejecuta: actualizar el saldo del conjunto de cuenta = 800 donde nombre = 'lilei';
  • El cliente B bloqueará cualquier fila de la tabla.

Los bloqueos de fila de InnoDB son bloqueos para índices, no bloqueos para registros. Y el índice no se puede invalidar, de lo contrario, se actualizará de bloqueo de fila a bloqueo de tabla.

En conclusión

Debido a que el motor de almacenamiento InnoDB implementa el bloqueo a nivel de fila, aunque el consumo de rendimiento del mecanismo de bloqueo puede ser mayor que el del bloqueo a nivel de tabla, es muy superior al bloqueo a nivel de tabla de MyISAM en términos de capacidad de procesamiento concurrente general.

Cuando la concurrencia del sistema es alta, el rendimiento general de InnoDB tendrá ventajas obvias en comparación con MyISAM.

Sin embargo, el bloqueo a nivel de fila de InnoDB también tiene su lado frágil: cuando lo usamos de manera incorrecta, el rendimiento general de InnoDB puede no ser superior al de MyISAM, pero puede incluso ser peor.

análisis de bloqueo de fila

Analice la contención de bloqueo de filas en su sistema examinando la variable de estado InnoDB_row_lock

show status like 'innodb_row_lock%';

inserte la descripción de la imagen aquí
La descripción de cada cantidad de estado es la siguiente:
Innodb_row_lock_current_waits: El número de bloqueos actualmente en espera
Innodb_row_lock_time: El tiempo total desde el inicio del sistema hasta el momento en que se bloquea el bloqueo
Innodb_row_lock_time_avg: El tiempo promedio empleado en cada espera
Innodb_row_lock_time_max: El tiempo de espera más largo desde el inicio del sistema hasta el presente
Innodb_row_lock_waits: Inicio del sistema Tiempos de espera totales desde entonces

Para estas cinco variables de estado, las más importantes son:
Innodb_row_lock_time_avg(tiempo medio de espera)
Innodb_row_lock_waits(tiempos de espera totales)
Innodb_row_lock_time(Tiempo de espera total)
Especialmente cuando la cantidad de tiempos de espera es alta y cada tiempo de espera no es pequeño, debemos analizar por qué hay tantas esperas en el sistema y luego comenzar a formular un plan de optimización basado en los resultados del análisis. .

Ver la hoja de datos relacionada con el bloqueo de la biblioteca del sistema INFORMATION_SCHEMA

--查看事务 
select * from INFORMATION_SCHEMA.INNODB_TRX;
-- innodb_locks表在8.0.13版本中由performance_schema.data_locks表所代替
--查看锁 
select * from INFORMATION_SCHEMA.INNODB_LOCKS;
--查看锁等待
--innodb_lock_waits表则由performance_schema.data_lock_waits表代替。
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

--释放锁trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id;
--查看锁等待详细信息 mysql8.0去掉\G
show engine innodb status\G;

punto muerto

El cliente A ejecuta: seleccione * de la cuenta donde id=1 para actualizar;
el cliente B ejecuta: seleccione * de la cuenta donde id=2 para actualizar;
el cliente A ejecuta: seleccione * de la cuenta donde id=2 para actualizar;
el cliente B ejecuta: seleccione * de cuenta donde id=1 para actualización;

Ver información de registro de interbloqueo reciente: mostrar el estado innodb del motor; en la mayoría de los casos, mysql puede detectar automáticamente el interbloqueo y revertir la transacción que causó el interbloqueo, pero en algunos casos mysql no puede detectar automáticamente el interbloqueo

Recomendaciones de optimización de bloqueo

  1. En la medida de lo posible, toda la recuperación de datos se realiza a través del índice para evitar la escalada de bloqueos de filas que no son de índice a bloqueos de tablas.
  2. Índices de diseño razonable para minimizar el alcance de los bloqueos
  3. Minimice el rango de condiciones de recuperación tanto como sea posible para evitar bloqueos de brecha
  4. Intente controlar el tamaño de la transacción, reduzca la cantidad de recursos de bloqueo y el tiempo, e intente ejecutar el SQL que involucra el bloqueo de transacciones al final de la transacción.
  5. Aislamiento de transacciones de bajo nivel posible

Supongo que te gusta

Origin blog.csdn.net/upset_poor/article/details/122982584
Recomendado
Clasificación