Análisis y soluciones al punto muerto de la base de datos causado por la fusión del índice MySQL | Equipo técnico de JD Cloud

fondo

En DBS-Cluster List-More-Connection Query-Deadlock, vi un registro de interbloqueo de la base de datos el 22 de septiembre. Después de la investigación, descubrí que el interbloqueo de la base de datos fue causado por la combinación del índice de optimización de mysql.

definición

Fusión de índices: una tecnología para la optimización de consultas de bases de datos, introducida después de MySQL 5.1. Puede realizar consultas en múltiples índices y fusionar los resultados.

Mecanismo de bloqueo de la base de datos MySQL

Antes de solucionar el problema, primero hable sobre el mecanismo de bloqueo de la base de datos MySQL:

1 La unidad básica de bloqueo es el bloqueo de siguiente tecla (bloqueo de registro + bloqueo de espacio). Cuando el bloqueo de registro o el bloqueo de espacio pueden resolver el problema de la lectura fantasma, degenerará en bloqueo de registro (bloqueo de fila) y bloqueo de espacio.

2 El bloqueo agrega bloqueos al índice, no a los datos.

3 Para la lectura actual, el índice está bloqueado. La declaración de lectura actual incluye (seleccionar... de... para actualizar, seleccionar... de... bloquear en modo compartido, actualizar..., eliminar . ...).

4. El bloqueo se distingue según el índice único y el índice no único. Según las condiciones de la consulta, se divide en consulta de igual valor y consulta de rango. Según si se pueden encontrar los datos, se divide en existencia de registro y no- existencia.

El índice utilizado en este problema de punto muerto es la existencia de registros en la consulta equivalente del índice no único, por lo que este artículo solo presenta esta situación en detalle. Para otras situaciones, puede consultar el documento de referencia 1 en la parte inferior:

La situación de bloqueo es: escaneará en secuencia. Primero, escaneará los datos que coincidan con la condición y agregará un bloqueo de siguiente clave. Luego escaneará el primer registro que no coincida con los datos, agregará un bloqueo de espacio, y finalmente encuentre la clave principal del registro. Agregue un bloqueo de registro,

Se han agregado tres tipos de bloqueos para la situación anterior. El propósito del bloqueo es evitar que se produzcan lecturas fantasma.

Analizar bloqueos en índices secundarios:

Estructura de la tabla:

CREATE TABLE `jdi_roster_apply_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `apply_id` varchar(100) NOT NULL COMMENT '申请单号',
  `status` tinyint(10) NOT NULL COMMENT '状态',
  PRIMARY KEY (`id`),
  KEY `idx_status` (`status`),
  KEY `idx_apply_id` (`apply_id`)
) ENGINE=InnoDB AUTO_INCREMENT=984483 DEFAULT CHARSET=utf8 COMMENT='黑白名单申请单明细'

Datos de la tabla:

identificación aplicar_id estado
959651 1695369220522068998 1
960738 1695369227576173690 1
961319 1695373047673903326 1
961365 1695373122447865228 1

árbol b+ establecido a través de idx_apply_id:

Debido a que el índice es un índice secundario, los datos almacenados en los nodos hoja son el valor de la clave principal.

Ejecutar sql:

select * from jdi_roster_apply_detail where apply_id='1695369227576173690' for update

Realizar el proceso de escaneo de datos

1 Busque el registro que cumpla las condiciones y agregue el siguiente candado de clave, de modo que el candado sea (1695369220522068998,1695369227576173690]

2 Encuentre los primeros datos que no coincidan con el registro y aumente el bloqueo de espacio, de modo que el bloqueo sea (1695369227576173690, 1695373047673903326)

3 Agregue un bloqueo de registro al índice de clave principal que cumpla con las condiciones, por lo tanto, agregue un bloqueo de registro a id = 960738.

Lectura fantasma para tres tipos de soluciones de cerraduras:

1 Si no hay un bloqueo de siguiente clave para el primer elemento y otra transacción agrega apply_id=1695369227576173690 e id<960738, la transacción tendrá un registro más al realizar la consulta, lo que provocará una lectura fantasma.

2 Si no hay un segundo bloqueo de espacio y se agrega otra transacción apply_id=1695369227576173690, id>960738, la transacción tendrá un registro más al realizar la consulta, lo que provocará una lectura fantasma.

3. Si no hay un tercer bloqueo de registro y otra transacción elimina un registro con id=960738, habrá un dato menos cuando la transacción consulte, lo que provocará una lectura fantasma.

Análisis de problemas prácticos.

Registro de interbloqueo de la base de datos

Las dos transacciones en el registro anterior ejecutaron declaraciones de actualización respectivamente:

#事务1
update jdi_roster_apply_detail set `status` = 10 where `status` = 1 and apply_id = '1695369220522068998'
#事务2
update jdi_roster_apply_detail set `status` = 10 where `status` = 1 and apply_id = '1695369227576173690' 

Este SQL se utiliza para cambiar los datos pendientes de aprobación de una determinada ID de aplicación a aprobados.

Debido a que la declaración de actualización no se puede ejecutar en Taishan, se ejecuta la declaración de selección para verificar el estado del índice:

explain select * from  jdi_roster_apply_detail  where `status` = 1 and apply_id = '1695369220522068998'

Resultado de la ejecución:

Se puede ver en los resultados que ambas declaraciones de actualización utilizan dos índices, a saber, idx_status e idx_apply_id. Los resultados encontrados luego se fusionan, por lo que durante el proceso de simulación se pueden dividir en dos declaraciones de consulta.

Simulación de punto muerto

Transacción 1 Transacción 2 rango de bloqueo
comenzar comenzar  
seleccione * de jdi_roster_apply_detail donde apply_id = '1695369220522068998' para actualizar   idx_apply_id está bloqueado (-∞, 1695369220522068998], (1695369220522068998, 1695369227576173690) El índice de identificación de la clave principal está bloqueado id=959651
  seleccione * de jdi_roster_apply_detail donde apply_id = '1695369227576173690' para actualizar idx_apply_id está bloqueado (1695369220522068998, 1695369227576173690], (1695369227576173690, 1695373047673903326) El índice de identificación de clave principal está bloqueado id=960738
seleccione * de jdi_roster_apply_detail donde estado = 1 para actualizar   Los bloqueos de siguiente clave y los bloqueos de espacio se agregarán a idx_status, pero cuando se agregan bloqueos de registro a las claves primarias 959651, 960738, 961319 y 961365, la transacción 2 ya agregó bloqueos de registro a 960738, por lo que la transacción 1 está bloqueada.
  seleccione * de jdi_roster_apply_detail donde estado = 1 para actualizar Los bloqueos de siguiente clave y los bloqueos de espacio se agregarán a idx_status, pero cuando se agregan bloqueos de registro a las claves primarias 959651, 960738, 961319 y 961365, la transacción 1 ya agregó bloqueos de registro a 959651, por lo que la transacción 2 está bloqueada.
  punto muerto  

Cada una de dos transacciones desea bloquear registros para dos ID de clave principal, lo que hace que la otra espere y forme un punto muerto.

Lo anterior es ejecutar primero la consulta de índice de idx_apply_id y luego la consulta de índice de idx_status. Si la consulta de índice de idx_status se ejecuta primero y luego la consulta de índice de idx_apply_id, también se producirá un punto muerto debido al bloqueo de registro del primario. llave.

solución

1 Utilice force index(idx_apply_id) para forzar un índice de modo que InnoDB ignore la combinación de índices y evite que se bloqueen varios índices al mismo tiempo.

2 Deshabilitar la combinación de índices Utilice el comando para deshabilitar la combinación de índices: SET GLOBAL optimizador_switch='index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off';

3 Index Merge usa dos índices independientes al mismo tiempo, así que cree un nuevo índice conjunto que contenga todos los campos de estos dos índices, de modo que InnoDB solo use este índice conjunto separado.

La tercera solución tiene un mejor rendimiento de consulta que la primera. En comparación con la segunda solución, solo afecta la tabla y tiene un alcance de impacto menor, por lo que esta solución también se adopta esta vez.

Resumir

El problema del punto muerto fue causado por el uso de un índice fusionado por parte del optimizador, que finalmente se resolvió creando un nuevo índice conjunto.

Documentación de referencia:

1 https://www.xiaolincoding.com/mysql/lock/how_to_lock.html

Autor: JD Industrial Li Xiaohui

Fuente: Comunidad de desarrolladores de JD Cloud Indique la fuente al reimprimir

El autor del marco de código abierto NanUI pasó a vender acero y el proyecto fue suspendido. La primera lista gratuita en la App Store de Apple es el software pornográfico TypeScript. Acaba de hacerse popular, ¿por qué los grandes empiezan a abandonarlo? Lista de octubre de TIOBE: Java tiene la mayor caída, C# se acerca Java Rust 1.73.0 lanzado Un hombre fue alentado por su novia AI a asesinar a la Reina de Inglaterra y fue sentenciado a nueve años de prisión Qt 6.6 publicado oficialmente Reuters: RISC-V La tecnología se convierte en la clave de la guerra tecnológica entre China y Estados Unidos. Nuevo campo de batalla RISC-V: no controlado por ninguna empresa o país, Lenovo planea lanzar una PC con Android.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/10117355
Recomendado
Clasificación