English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Análisis del problema de MDL LOCK (MDL LOCK) en MYSQL METADATA LOCK

I. Introducción

El bloqueo MDL en MYSQL ha sido un problema bastante molesto, cuando hablamos de bloqueos, generalmente tendemos a inclinarnos hacia el nivel inferior de INNODB, como gap lock, next key lock, row lock, etc., porque son fáciles de entender y observar, mientras que el MDL LOCK se conoce muy poco, ya que es difícil de observar, solo se puede ver con difficulty show processlist cuando hay problemas

El estado simplemente llamado Waiting for table metadata lock, en realidad MDL LOCK es un subsistema muy complejo en el nivel superior de MYSQL, con su propio mecanismo de detección de bloqueos

(grafo no dirigido&63;) Y lo que todos suelen decir que es un bloqueo de tabla en realidad se refiere a esto, lo que muestra su importancia y gravedad. El autor también ha aprendido algo (punta del iceberg) según sus necesidades, pero no tiene la capacidad de leer todo el código. Sin embargo, el autor ha añadido una función de impresión de TICKET para que todo el flujo de bloqueo MDL LOCK se imprima por completo, facilitando el aprendizaje y la investigación. A continuación, se hablará de algunos conceptos básicos y se informará sobre qué se ha modificado, y finalmente se realizarán pruebas y análisis de cada tipo de MDL TYPE. Si no les interesa el concepto básico y la adición de la función de impresión, pueden referirse directamente a la sección de pruebas de bloqueo en la parte cinco, pero si no conocen los fundamentos, puede ser un poco difícil de entender.

刚好最近遇到一次MDL LOCK出现死锁的情况会在下篇文章中给出案例,这里只看理论

----处于层次:MYSQL SERVER层次,实际上早在open_table函数中MDL LOCK就开始获取了,可以说他是最早获取的LOCK结构

----最早获取阶段: THD::enter_stage: 'Opening tables'

调用栈帧

#0 open_table_get_mdl_lock (thd=0x7fffd0000df0, ot_ctx=0x7fffec06fb00, 
  table_list=0x7fffd00067d8, flags=0, mdl_ticket=0x7fffec06f950)
  at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_base.cc:2789
#1 0x0000000001516e17 在 open_table (thd=0x7fffd0000df0, 
  table_list=0x7fffd00067d8, ot_ctx=0x7fffec06fb00)
  at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_base.cc:3237

----死锁检测出错码:

{"ER_LOCK_DEADLOCK", 1213, "当尝试获取锁时发现死锁;尝试重新启动事务"
ERROR 1213 (40001当尝试获取锁时发现死锁;尝试重新启动事务

MDL LOCK的死锁抛错和INNODB死锁一模一样不同的只是SHOW ENGINE INNODB 没有死锁信息。

----涉及代码:mdl.h mdl.cc

二、基础重要的数据结构(类)和概念

1、MDL TYPE

MDL_INTENTION_EXCLUSIVE(IX)

MDL_SHARED(S)

MDL_SHARED_HIGH_PRIO(SH)

MDL_SHARED_READ(SR)

MDL_SHARED_WRITE(SW)

MDL_SHARED_WRITE_LOW_PRIO(SWL)

MDL_SHARED_UPGRADABLE(SU)

MDL_SHARED_READ_ONLY(SRO)

MDL_SHARED_NO_WRITE(SNW)

MDL_SHARED_NO_READ_WRITE(SNRW)

MDL_EXCLUSIVE(X)

接下来会对每种TYPE进行详细的测试,最后也会给出源码中的解释

2、MDL NAMESPACE

在MDL中,MDL_KEY按照NAMESPACE+DB+使用OBJECT_NAME的方式进行表示,所谓的namespace也不那么重要

以下是NAMESPACE的分类

- GLOBAL se utiliza para el bloqueo de lectura global.

- TABLESPACE es para tablespaces.

- SCHEMA es para esquemas (también conocido como bases de datos).

- TABLE es para tablas y vistas.

- FUNCTION es para funciones almacenadas.

- PROCEDURE es para procedimientos almacenados.

- TRIGGER es para disparadores.

- EVENT es para eventos del planificador de eventos.

- COMMIT es para habilitar el bloqueo de lectura global para bloquear los compromisos.

- USER_LEVEL_LOCK es para el usuario-nivel de bloqueo.

- LOCKING_SERVICE es para el complemento de nombre RW-servicio de bloqueo

3、实现分类

范围锁定:通常对应全局MDL LOCK,如flush table with read lock 为namespace space:GLOBAL type:S

对象锁定:如其名,对象级别的MDL LOCK,例如TABLE

以下是源代码中的注释:

 /**
  辅助结构,它定义了如何处理不同类型的锁定
  对于特定的MDL_lock。在实践中,我们只使用两种策略:"范围"
  在GLOBAL、COMMIT、TABLESPACE和SCHEMA命名空间中的锁定策略
  以及所有其他命名空间的对象锁定策略。
 */

4、MDL兼容矩阵

范围锁定:
     | 活跃类型的类型 |
 请求 | 范围锁定  |
  类型  | IS(*) IX  S X |
 ---------+------------------+
 IS    | +   +  + + |
 IX    | +   +  - - |
 S    | +   -  + - |
 X    | +   -  - - |
对象锁定:
    请求 | 已授予的锁定请求      |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   S     | +  +  +  +  +  +  +  +  +  - |
   SH    | +  +  +  +  +  +  +  +  +  - |
   SR    | +  +  +  +  +  +  +  +  -  - |
   SW    | +  +  +  +  +  +  -  -  -  - |
   SWLP   | +  +  +  +  +  +  -  -  -  - |
   SU    | +  +  +  +  +  -  +  -  -  - |
   SRO | +  +  +  -  -  +  +  +  -  - |
   SNW    | +  +  +  -  -  -  +  -  -  - |
   SNRW | +  +  -  -  -  -  -  -  -  - |
   X     | -  -  -  -  -  -  -  -  -  - |

5、MDL持续时间及MDL持续到何时

Este no requiere muchas explicaciones, simplemente revise los comentarios del código fuente

MDL_STATEMENT: Los bloqueos con duración de instrucción se liberan automáticamente al final
       de la sentencia o transacción.
MDL_TRANSACTION: Los bloqueos con duración de transacción se liberan automáticamente al final
        de la transacción
MDL_EXPLICIT: Los bloqueos con duración explícita sobreviven al final de la instrucción y la transacción.
       Tienen que ser liberados explícitamente llamando a MDL_context::release_lock().

6、MDL LOCK FAST PATH (invasivo) O SLOW PATH (no invasivo)

El uso de dos métodos diferentes tiene como objetivo optimizar la implementación de MDL lock, a continuación se muestra el comentario del código fuente

A) "unobtrusive" lock types
      1) Each type from this set should be compatible with all other
        types from the set (including itself).
      2) These types should be common for DML operations
     Our goal is to optimize acquisition and release of locks of this
     type by avoiding complex checks and manipulations on m_waiting/
     m_granted bitmaps/lists. We replace them with a check of and
     increment/decrement of integer counters.
     We call the latter type of acquisition/release "fast path".
     Use of "fast path" reduces the size of critical section associated
     with MDL_lock::m_rwlock lock in the common case and thus increases
     escalabilidad.
     La cantidad por la que la adquisición/liberación de un tipo específico
     El bloqueo "inobtrusivo" aumenta/disminuye el contador empacado en
     MDL_lock::m_fast_path_state es devuelto por esta función.
B) Tipos de bloqueo "obtrusivo"
      1) El bloqueo otorgado o pendiente de ese tipo es incompatibles con
        otros tipos de bloqueos o con ellos mismos.
      2) No común para operaciones DML
     Estos bloqueos deben ser siempre adquiridos involucrando manipulaciones en
     m_waiting/m_granted bitmaps/, es decir, debemos usar "ruta lenta"
     para ellos. Además, en presencia de listas activas/bloqueos pendientes de
     Conjunto "obtrusivo" que debemos obtener utilizando "ruta lenta", incluso los bloqueos de
     Tipo "inobtrusivo".

7Clase MDL_request

Es decir, la necesidad de MDL LOCK obtenida después de la análisis de la sentencia, luego a través de este objeto de clase en el subsistema MDL
Se realiza una solicitud de bloqueo MDL, que aproximadamente incluye las siguientes propiedades

/** Tipo de bloqueo de metadatos. */
 enum enum_mdl_type type; //Tipo de solicitud
 /** Duración del bloqueo solicitado. */
 enum enum_mdl_duration duration; //Duración
 /**
  Punteros para participar en la lista de solicitudes de bloqueo para este contexto.
 */
 MDL_request *next_in_list; //Implementación de lista enlazada bidireccional
 MDL_request **prev_in_list;
 /**
  Puntero al objeto del ticket de bloqueo para esta solicitud de bloqueo.
  Válido solo si esta solicitud de bloqueo se satisface.
 */
 MDL_ticket *ticket; //Nota: si la solicitud es exitosa (sin esperar), se referirá a un ticket real, de lo contrario será NULL
 /** Se solicita un bloqueo basado en un nombre completamente cualificado y tipo. */
 MDL_key key;//Nota: aquí es un tipo MDL_KEY, que es principalmente lo que se mencionó anteriormente como NAMESPACE+DB+OBJECT_NAME

clase MDL_key, que es el NAMESPACE real+DB+OBJECT_NAME, todo se coloca en un array de char, que aparecerá en MDL_LOCK y MDL_REQUEST

private:

uint16 m_length;

uint16 m_db_name_length;

char m_ptr[MAX_MDLKEY_LENGTH];//se colocó aquí

8、MDL_ticket

Como un boleto, si se obtiene MDL LOCK, se devuelve un boleto a MDL_request, si se espera, no se origina el código MDL_context::acquire_lock

Se puede observar. Por supuesto, también es una de las clases que he observado principalmente

/**
  Punteros para participar en la lista de solicitudes de bloqueo para este contexto.
  Contexto privado. Como se explica aquí, es la formación de la lista enlazada en el contexto, que es privada del hilo
 */
 MDL_ticket *next_in_context;
 MDL_ticket **prev_in_context;
 /**
  Punteros para participar en la lista de satisfechos/solicitudes pendientes
  para el bloqueo. Accesible externamente. Como se explica aquí, es la formación de la lista enlazada de MDL_LOCK, que es global
 */
 MDL_ticket *next_in_lock;
 MDL_ticket **prev_in_lock;
/**
  Contexto del propietario del ticket de bloqueo de metadatos. Accesible externamente.
  Claramente aquí se refiere al propietario de este ticket, es decir, MDL_context, que es una propiedad del hilo
 */
 MDL_context *m_ctx; 
 /**
  Pointer to the lock object for this lock ticket. Externally accessible.
  It is obvious that here is a pointer to MDL_LOCK
 */
 MDL_lock *m_lock;
 /**
  Indicates that the ticket corresponds to a lock acquired using "fast path"
  algorithm. Particularly this means that it was not included into
  MDL_lock::m_granted bitmap/list and instead is accounted for by
  MDL_lock::m_fast_path_locks_granted_counter
  Here it represents whether it is a FAST PATH. From the comments, it can be seen that the fast path method will not be included in the MDL LOCK
  Instead of occupying the granted bitmap and list, a counter m_fast_path_locks_granted_counter is used
  In this way, the cost is definitely lower
 */
 bool m_is_fast_path;
 /**
  Indicates that the ticket corresponds to a lock request that required
  storage engine notification during its acquisition and requires
  storage engine notification after its release.
 */
 bool m_hton_notified;

9、MDL_lock

Each MDL_key corresponds to an MDL_lock, which includes the so-called GRANTED list and WAIT list. Considering its complexity, it is recommended to directly refer to the source code comments, which are very detailed. Here are several properties that I describe.

/** The key of the object (data) being protected. */

MDL_key key;

/** List of granted tickets for this lock. */

Ticket_list m_granted;

/** Tickets for contexts waiting to acquire a lock. */

Ticket_list m_waiting;

10de MDL_context

Esto es una estructura de contexto llamada supuesta del sistema de interacción entre el hilo y el bloqueo de MDL de MYSQL completo, que contiene muchos métodos y propiedades, las propiedades que me interesan son las siguientes:

/**
  Si nuestra solicitud de un bloqueo está programada o abortada por el bloqueo
  detector, el resultado se registra en esta clase.
 */
 MDL_wait m_wait;
/**
  Listas de todos los tickets de MDL adquiridos por esta conexión.
  Esto es un array de listas de diferentes duraciones de bloqueo de MDL. En realidad es
  MDL_STATEMENT una lista
  MDL_TRANSACTION una lista
  MDL_EXPLICIT una lista
 */
Ticket_list m_tickets[MDL_DURATION_END];
//Esto es un puntero de clase padre apuntando a un objeto de subclase, un ejemplo típico de sobrescritura de función virtual, en realidad apunta a un hilo
/*
class THD :public MDL_context_owner,
      public Query_arena,
      public Open_tables_state
*/
MDL_context_owner *m_owner;

11de espera de MDL

Esta clase es principalmente el estado actual de obtención de ticket

enum_wait_status m_wait_status;

contiene

EMPTY Inicialización

GRANTED Éxito en la adquisición

VICTIM Víctima de bloqueo

TIMEOUT Tiempo de espera excedido

KILLED KILLED

12de espera de marca

PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
{
 {0, "Esperando el bloqueo de lectura global", 0},
 {0, "Esperando el bloqueo de metadatos del espaciotabla", 0},
 {0, "Esperando el bloqueo de metadatos del esquema", 0},
 {0, "Esperando el bloqueo de metadatos de la tabla", 0},
 {0, "Esperando por el bloqueo de metadatos de función almacenada", 0}
 {0, "Esperando por el bloqueo de metadatos de procedimiento almacenado", 0},
 {0, "Esperando por el bloqueo de metadatos de gatillo", 0},
 {0, "Esperando por el bloqueo de metadatos de evento", 0},
 {0, "Esperando por el bloqueo de compromiso", 0},
 {0, "Bloqueo de usuario", 0}, /* Ser compatible con el estado antiguo. */
 {0, "Esperando por el bloqueo del servicio de bloqueo", 0},
 {0, "Esperando por el bloqueo de respaldo", 0},
 {0, "Esperando por el bloqueo de binlog", 0}
};

Tercero, agregar la función de impresión de MDL LOCK

la mejor manera de estudiar el bloqueo MDL LOCK es poder obtener el flujo de bloqueo, actualización y downgrade de MDL, ya que el código fuente es demasiado grande y es imposible abarcarlo todo
aunque5.7se añadió

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME ='global_instrumentation';

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME ='wait/lock/metadata/sql/mdl';

select * from performance_schema.metadata_locks

para ver MDL LOCK de esta manera, pero si se desea observar qué MDL LOCK ha obtenido una declaración específica, se siente algo ineficaz, por lo que el autor agregó un prototipo de función en mdl.cc

/*p_ticket en parámetro*/

int my_print_ticket(const MDL_ticket* p_ticket)

y se añadió este prototipo de función amiga en la clase mdl_ticket, de lo contrario, no se puede acceder a los miembros privados, y los métodos públicos proporcionados son bastante complejos

amigo int my_print_ticket(const MDL_ticket* p_ticket);}

Principalmente obtener la información siguiente del MDL LOCK y escribir en el registro de errores de mysql:

id de hilo a través de p_ticket->m_ctx->get_thd(); obtener

mdl lock database name a través de p_ticket->m_lock->key.db_name() obtener

mdl lock object name a través de p_ticket->m_lock->key.name() obtener

mdl lock namespace a través de p_ticket->m_lock->key.mdl_namespace() obtener

mdl lock fast path a través de p_ticket->m_is_fast_path obtener juicio es entonces salida, de lo contrario no salida

mdl lock type a través de p_ticket->m_type obtener

mdl lock duration a través de p_ticket->m_duration obtener

La información de salida es como sigue:

2017-08-03T07:34:21.720583Z 3 [Nota] (>MDL PRINT) El id de hilo es 3:

2017-08-03T07:34:21.720601Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test

2017-08-03T07:34:21.720619Z 3 [Nota] (-->IMPRESIÓN DE MDL) NOMBRE_DE_OBJETO ES: test

2017-08-03T07:34:21.720637Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA

2017-08-03T07:34:21.720655Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)

2017-08-03T07:34:21.720673Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED_WRITE (SW)

2017-08-03T07:34:21.720692Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION

En realidad, es más o menos la misma información que en metadata_locks, este es el id de Thread que sale de show processlist, pero puedo obtener la información histórica de obtención de bloqueos, aquí no tengo ESTADO_DE_BLOQUEO: CONCEDIDO, pero puedo juzgarlo lógicamente en la lógica MDL_context::acquire_lock

mysql> select * de performance_schema.metadata_locks\G
*************************** 1fila. ***************************
TIPO_DE_OBJETO: TABLA
ESQUEMA_DE_OBJETO: test
NOMBRE_DE_OBJETO: test
INICIO_DE_INSTANCIA_DE_OBJETO: 140734412907760
TIPO_DE_BLOQUEO: ESCRITURA_COMPARTIDA
DURACIÓN_DE_BLOQUEO: TRANSACCIÓN
ESTADO_DE_BLOQUEO: CONCEDIDO
FUENTE: sql_parse.cc:6314
OWNER_THREAD_ID: 39
OWNER_EVENT_ID: 241

Cuatro, agregar funciones de impresión en las posiciones adecuadas para observar

Si vamos a estudiar el bloqueo, la promoción y la despromoción de MDL LOCK, es necesario encontrar sus puntos de entrada a las funciones, luego agregar funciones de impresión en las posiciones adecuadas para observar, a continuación, se indica la posición de impresión, se eliminó la mayor parte del código fuente, para referencias, consulte el código fuente por su cuenta

1、bloquear: MDL_context::acquire_lock

bool
MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
{
 if (mdl_request->ticket) //Se obtuvo con éxito el ticket
 {
  /*
   Hemos logrado obtener el bloqueo sin esperar.
   MDL_lock, MDL_context y MDL_request fueron actualizados
   por lo tanto, podemos simplemente regresar el éxito.
  */
  //REQUESET obtuvo TICKET con éxito, aquí se imprime
  return FALSE;
 }
 /*
  Nuestro intento de obtener el bloqueo sin esperar ha fallado.
  Como resultado de este intento, obtuvimos MDL_ticket con m_lock
  miembro apuntando al objeto MDL_lock correspondiente que
  tiene MDL_lock::m_rwlock write-bloqueado.
 */
 //No se pudo obtener, se une a la cola de espera MDL_lock
 lock = ticket->m_lock;
 lock->m_waiting.add_ticket(ticket);
 will_wait_for(ticket); //Detección de bloqueo
 /* Hay un bloqueo compartido o exclusivo en el objeto. */
 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
 find_deadlock(); 
 //Aquí se imprime que el TICKET entró en el flujo de espera
 if (lock->necesita_notificación(ticket) || lock->necesita_comprobación_de_conexión())
 {
  }
 done_waiting_for();//Después de completar la espera, ajustamos el grafo de detección de bloqueo eliminando este borde de espera edge (grafo no dirigido)
 //Por supuesto, aquí también se obtuvo éxito después de esperar, el estado es GRANTED
 DBUG_ASSERT(esperar_estado == MDL_wait::GRANTED);
 m_tickets[mdl_request]->duration].push_front(ticket);
 mdl_request->ticket= ticket;
 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
 //此处打印通过等待REQUEST获得了TICKET
 return FALSE;
}

2、降级:void MDL_ticket::downgrade_lock(enum_mdl_type new_type)

void MDL_ticket::downgrade_lock(enum_mdl_type new_type)
{
 /* Only allow downgrade from EXCLUSIVE and SHARED_NO_WRITE. */
 DBUG_ASSERT(m_type == MDL_EXCLUSIVE ||
       m_type == MDL_SHARED_NO_WRITE);
//此处打印出降级前的TICKET
 if (m_hton_notified)
 {
  mysql_mdl_set_status(m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
  m_ctx,->get_owner(),->notify_hton_post_release_exclusive(&m_lock->key);
  m_hton_notified= false;
  mysql_mdl_set_status(m_psi, MDL_ticket::GRANTED);
 }
//函数结尾答应出降级后的TICKET
}

3、升级:MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,enum_mdl_type new_type, ulong lock_wait_timeout)

bool
MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,
                 enum_mdl_type new_type,
                 ulong lock_wait_timeout)
{
 MDL_REQUEST_INIT_BY_KEY(&mdl_new_lock_request,
             &mdl_ticket->m_lock->key, new_type,
             MDL_TRANSACTION);//Construir una solicitud
 //Aquí se imprime el tipo de TICKET 
 if (acquire_lock(&mdl_new_lock_request, lock_wait_timeout)) //Intentar usar el nuevo LOCK_TYPE para bloquear
  DBUG_RETURN(TRUE);
 is_new_ticket= ! has_lock(mdl_svp, mdl_new_lock_request.ticket);
 lock= mdl_ticket->m_lock;
 //A continuación, se realizan una serie de operaciones de mantenimiento en MDL_LOCK y se realizan operaciones de combinación
 /* El código a continuación asume que está actualizando a un tipo de bloqueo "obtrusive". */
 DBUG_ASSERT(lock->is_obtrusive_lock(new_type));
 /* Combinar el bloqueo adquirido y el original. @todo: mover a un método. */
 mysql_prlock_wrlock(&lock->m_rwlock);
 if (is_new_ticket)
 {
  m_tickets[MDL_TRANSACTION].remove(mdl_new_lock_request.ticket);
  MDL_ticket::destroy(mdl_new_lock_request.ticket);
 }
 //Aquí se imprime el tipo de TICKET después de la actualización 
 DBUG_RETURN(FALSE);
}

Por supuesto, ahora solo he impreso en estos lugares, en el futuro, si es necesario en otros lugares, se puede agregar una función.

V. Pruebas de bloqueo de varios tipos de MDL LOCK

1, MDL_INTENTION_EXCLUSIVE(IX)

Este bloqueo aparecerá en muchas operaciones, por ejemplo, al realizar cualquier DML/Las operaciones DDL desencadenan, en realidad DELETE/UPDATE/INSERT/Las operaciones DML como FOR UPDATE se aseguran de que se añada un bloqueo IX en GLOBAL antes de bloquear en este objeto, mientras que las sentencias DDL al menos añaden un bloqueo IX en GLOBAL, en el SCHEMA al que pertenece el objeto y en este objeto. A continuación, se muestra el bloqueo IX MDL LOCK desencadenado por DELETE

2017-08-03T18:22:38.092100Z 3 [Nota] Test2:open_tables_for_query()
2017-08-03T18:22:38.092205Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T18:22:38.092242Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T18:22:38.092276Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:GLOBAL 
2017-08-03T18:22:38.092310Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T18:22:38.092344Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:22:38.092380Z 3 [Nota] (------>MDL PRINT) Duración del MDL es:MDL_STATEMENT 
2017-08-03T18:22:38.092551Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

A continuación se muestra el bloqueo MDL GLOBAL IX desencadenado por la sentencia ALETER y el bloqueo MDL de nivel de SCHEMA

2017-08-03T18:46:05.894871Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T18:46:05.894915Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T18:46:05.894948Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:GLOBAL 
2017-08-03T18:46:05.894980Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T18:46:05.895012Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895044Z 3 [Nota] (------>MDL PRINT) Duración del MDL es:MDL_STATEMENT 
2017-08-03T18:46:05.895076Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T18:46:05.895116Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T18:46:05.895147Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T18:46:05.895206Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T18:46:05.895243Z 3 [Nota] (-->MDL PRINT) Nombre del objeto es: 
2017-08-03T18:46:05.895276Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:SCHEMA 
2017-08-03T18:46:05.895325Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T18:46:05.895357Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895390Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T18:46:05.895421Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Por lo tanto, este MDL LOCK está en todas partes, y solo hay un problema de compatibilidad. El tipo de bloqueo IX SCOPED generalmente es compatible, a menos que se encuentre
Tipo S

2、MDL_SHARED(S)

Este bloqueo generalmente se usa en flush tables with read lock

mysql> flush tables with read lock;
Consulta OK, 0 filas afectadas (0.01 seg)
2017-08-03T18:19:11.603911Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T18:19:11.603947Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T18:19:11.603971Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:GLOBAL 
2017-08-03T18:19:11.603994Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED(S) 
2017-08-03T18:19:11.604045Z 3 [Nota] (------>MDL PRINT) La duración del MDL es: MDL_EXPLICIT 
2017-08-03T18:19:11.604073Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T18:19:11.604133Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T18:19:11.604156Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T18:19:11.604194Z 3 [Nota] (--->MDL PRINT) El namespace es: COMMIT 
2017-08-03T18:19:11.604217Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED(S) 
2017-08-03T18:19:11.604240Z 3 [Nota] (------>MDL PRINT) La duración del MDL es: MDL_EXPLICIT 
2017-08-03T18:19:11.604310Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Notamos que su namespace es GLOBAL y COMMIT, obviamente son SCOPED LOCK, su TYPE es S, por lo que obviamente según el principio de compatibilidad
El MDL IX SCOPED y el MDL S no son compatibles, flush tables with read lock; bloqueará todos los DELTE/UPDATE/INSERT/FOR UPDATE
y otras operaciones DML y DDL (porque estas operaciones necesitan el bloqueo MDL IX GLOBAL)

3、MDL_SHARED_HIGH_PRIO(SH)

Este bloqueo también se usa con frecuencia por todos, pero no se siente, por ejemplo, la operación desc general

Compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SH    | +  +  +  +  +  +  +  +  +  - |
mysql> desc test.testsort10;
2017-08-03T19:06:05.843277Z 4 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T19:06:05.843324Z 4 [Nota] (>MDL PRINT) El id de hilo es 4: 
2017-08-03T19:06:05.843359Z 4 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:06:05.843392Z 4 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort10 
2017-08-03T19:06:05.843425Z 4 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:06:05.843456Z 4 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T19:06:05.843506Z 4 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED_HIGH_PRIO(SH) 
2017-08-03T19:06:05.843538Z 4 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:06:05.843570Z 4 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Este tipo de prioridad es relativamente alta, pero es incompatibles con X. También es fácil entender, por ejemplo, en la etapa de rename, no se puede realizar la operación desc.

4、MDL_SHARED_READ(SR)

Este bloqueo generalmente se usa en select que no son de lectura actual, compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SR    | +  +  +  +  +     +   +    +  -  - |
mysql> select * from test.testsort10 limit 1;
2017-08-03T19:13:52.338764Z 4 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T19:13:52.338813Z 4 [Nota] (>MDL PRINT) El id de hilo es 4: 
2017-08-03T19:13:52.338847Z 4 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:13:52.338883Z 4 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort10 
2017-08-03T19:13:52.338917Z 4 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:13:52.338950Z 4 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T19:13:52.339025Z 4 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED_READ(SR) 
2017-08-03T19:13:52.339062Z 4 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:13:52.339097Z 4 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Aún hay que mencionar que a veces select también se bloquea, por ejemplo, en alguna etapa de DDL que necesita el bloqueo MDL X del objeto MDL). No podemos evitar quejarnos
MYSQL realmente puede bloquear select, aquí es un problema de incompatibilidad entre object mdl lock X y SR (ver la matriz de compatibilidad anterior).

5、MDL_SHARED_WRITE (SW)

Este bloqueo generalmente se utiliza para DELTE/UPDATE/INSERT/Operaciones como FOR UPDATE que bloquean la tabla (lectura actual), no incluyen operaciones DDL
pero debes tener en cuenta que la operación DML realmente tendrá un bloqueo de IX GLOBAL, como se mencionó anteriormente, este bloqueo es solo en el objeto

Compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SW    | +  +  +  +  +  +  -  -  -  - |
mysql> select * from test.testsort10 limit 1 for update;
2017-08-03T19:25:41.218428Z 4 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T19:25:41.218461Z 4 [Nota] (>MDL PRINT) El id de hilo es 4: 
2017-08-03T19:25:41.218493Z 4 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:25:41.218525Z 4 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort10 
2017-08-03T19:25:41.218557Z 4 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:25:41.218588Z 4 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T19:25:41.218620Z 4 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED_WRITE (SW) 
2017-08-03T19:25:41.218677Z 4 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:25:41.218874Z 4 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

6、MDL_SHARED_WRITE_LOW_PRIO (SWL)

Este bloqueo se utiliza raramente, los comentarios de código fuente solo

Usado por sentencias DML que modifican

tablas y utilizando la cláusula LOW_PRIORITY

se utiliza

Compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SWLP   | +  +  +  +  +  +  -  -  -  - |
mysql> update LOW_PRIORITY test.testsort10 set id1=1000 donde id1= 96282;
2017-08-03T19:32:47.433507Z 4 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T19:32:47.433521Z 4 [Nota] (>MDL PRINT) El id de hilo es 4: 
2017-08-03T19:32:47.433533Z 4 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:32:47.433547Z 4 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort10 
2017-08-03T19:32:47.433560Z 4 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:32:47.433572Z 4 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T19:32:47.433594Z 4 [Nota] (----->MDL PRINT) El tipo de MDL es: MDL_SHARED_WRITE_LOW_PRIO (SWL) 
2017-08-03T19:32:47.433607Z 4 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:32:47.433620Z 4 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

7、MDL_SHARED_UPGRADABLE (SU)

Este bloqueo generalmente se utiliza en la sentencia ALTER TABLE, puede subir a SNW, SNRW, X, y al menos el bloqueo X también puede descender a SU

En realidad, en la DDL en línea de INNODB depende mucho de él, DML (SW) y SELECT (SR) no bloquean

Compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SU    | +  +  +  +  +  -  +  -  -  - |

Es necesario estudiar su compatibilidad, podemos ver que en OBJECT LOCK (SELECT) SR (DML) SW son permitidos, y en el SCOPED LOCK
Aunque DML y DDL bloquearán en GLOBAL, su tipo son IX, por lo que este bloqueo de SU no bloquea DML/La operación de SELECT y escritura entra en la capa del motor INNODB, que es la base de la DDL en línea, si no es compatible no puedes entrar en la capa del motor INNODB, mucho menos hablar de DDL en línea, ten en cuenta que aquí digo ALGORITHM=INPLACE y sin establecer LOCK

(Para operaciones de DDL con LOCK=DEFAULT o sin cláusula LOCK, MySQL utiliza el nivel más bajo
el bloqueo disponible para ese tipo de operación, permitiendo consultas concurrentes, DML o ambas dondequiera que sea
posible. Esta es la configuración que debe usar al hacer pre-planeado, pre-cambios probados que sabes que no
causar problemas de disponibilidad basados en la carga de trabajo de esa tabla
Cuando una operación sobre la clave principal utiliza ALGORITHM=INPLACE, aunque los datos aún se copian, es
es más eficiente que usar ALGORITHM=COPY porque:
? No se requiere registro de deshacer o registro de redo asociado para ALGORITHM=INPLACE. Estas operaciones agregan
costo adicional para las declaraciones DDL que utilizan ALGORITHM=COPY.
? Las entradas del índice secundario son pre-ordenados, por lo que se pueden cargar en orden.
? El búfer de cambio no se utiliza, porque no hay aleatorios-insertar en índices secundarios.
)

como sigue la siguiente instrucción

mysql> modificar tabla testsort12 agregar columna it int no nulo;
Consulta OK, 0 filas afectadas (6.27 seg)
Registros: 0 Duplicados: 0 Advertencias: 0

Analizaré de manera simple:

2017-08-03T19:46:54.781453Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T19:46:54.781487Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T19:46:54.781948Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:46:54.781990Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T19:46:54.782026Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:46:54.782060Z 3 [Nota] (----->IMPRESIÓN MDL) El tipo de MDL es: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.782096Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:46:54.782175Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T19:46:54.803898Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBIRÁ
2017-08-03T19:46:54.804201Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBE A
2017-08-03T19:46:54.804240Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T19:46:54.804254Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:46:54.804267Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T19:46:54.804280Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:46:54.804293Z 3 [Nota] (----->IMPRESIÓN MDL) Tipo de MDL: MDL_EXCLUSIVO(X) 
2017-08-03T19:46:54.804306Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T19:46:54.855563Z 3 [Nota] (descenso_de_bloqueo)ESTE BLOQUEO MDL SE DESCENDRÁ
2017-08-03T19:46:54.855693Z 3 [Nota] (downgrade_lock) A ESTE BLOQUEO MDL
2017-08-03T19:46:54.855706Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T19:46:54.855717Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:46:54.856053Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T19:46:54.856069Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:46:54.856082Z 3 [Nota] (----->IMPRESIÓN MDL) El tipo de MDL es: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.856094Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:46:54.856214Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T19:47:00.260166Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBIRÁ
2017-08-03T19:47:00.304057Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBE A
2017-08-03T19:47:00.304090Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T19:47:00.304105Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:47:00.304119Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T19:47:00.304132Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:47:00.304181Z 3 [Nota] (----->MDL PRINT) El tipo de Mdl es:MDL_EXCLUSIVE(X) 
2017-08-03T19:47:00.304196Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:47:00.304211Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T19:47:01.032329Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito! 

primero obtener testsort12sobre la tabla

2017-08-03T19:46:54.781487 obtener MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:46:54.804293 subir MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.855563 descender MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:47:00.304057 subir MDL_EXCLUSIVE(X) 

Porque, sin importar cómo sea, esta operación ALTER es bastante costosa, como podemos ver2017-08-03T19:46:54se completa el descenso a2017-08-03T19:47:00 en este período
En realidad, es lo más costoso, es aquí donde se realiza la operación real de COPY, pero este proceso realmente se realiza en el modo MDL SU, por lo que no bloquea DML/operaciones SELECT.
Aquí les recuerdo que lo que se llama ONLINE DDL solo no bloquea DML en la fase de COPY/operaciones SELECT, es mejor que se realicen cuando la presión en la base de datos es baja
por ejemplo, si hay DML sin comprometer o SELECT sin completar, entonces SW SR necesariamente bloquea X, y X puede bloquear todo y tiene una prioridad alta. Esto lleva a
El fenómeno es debido a que DML no se ha comprometido y bloquea la operación DDL, y la operación DDL bloquea todas las operaciones, básicamente bloquea todas las tablas de esta TABLE. Mientras que para ALGORITHM=COPY otras partes son más o menos iguales, pero en la fase de COPY se utiliza el bloqueo SNW, por lo que primero echaré un vistazo al bloqueo SNW

8、MDL_SHARED_NO_WRITE(SNW)

SU puede actualizarse a SNW y SNW puede actualizarse a X, como se mencionó anteriormente, se utiliza en ALGORITHM=COPY para proteger la consistencia de los datos.
Veamos su compatibilidad primero

   Solicitud | Solicitud concedida para el bloqueo          
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNW    | +  +  +  -  -  -  +  -  -  - |

Se puede ver que SR puede pero SW no, por supuesto, también bloquea DML(SW) pero SELECT(SR) no bloquea, aquí solo se proporciona la parte clave

mysql> modificar tabla testsort12 se añade la columna ik int no nulo, ALGORITHM=COPY ;
2017-08-03T20:07:58.413215Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBE A
2017-08-03T20:07:58.413241Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T20:07:58.413257Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T20:07:58.413273Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T20:07:58.413292Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T20:07:58.413308Z 3 [Nota] (----->IMPRESIÓN MDL) El tipo de MDL es: MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:07:58.413325Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T20:07:58.413341Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T20:08:25.392006Z 3 [Nota] (upgrade_shared_lock)ESTE BLOQUEO MDL SE SUBE A
2017-08-03T20:08:25.392024Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T20:08:25.392086Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T20:08:25.392159Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T20:08:25.392199Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T20:08:25.392214Z 3 [Nota] (----->MDL PRINT) El tipo de Mdl es:MDL_EXCLUSIVE(X) 
2017-08-03T20:08:25.392228Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T20:08:25.392242Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T20:07:58.413308 obtuvo MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:08:25.392006 sube a MDL_EXCLUSIVE(X) 

esto2017-08-03T20:07:58.413308a2017-08-03T20:08:25.392006es el tiempo real de COPY, por lo que durante todo el período de COPY solo se puede realizar DML
Y no puede SELECT, también es una diferencia clave entre ALGORITHM=COPY y ALGORITHM=INPLACE.

9, MDL_SHARED_READ_ONLY(SRO)

Usado para la declaración LOCK TABLES READ

La compatibilidad es la siguiente

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SRO | +  +  +  -  -  +  +  +  -  - |
Bloquea DML(SW) pero SELECT(SR) sigue siendo posible.
mysql> lock table testsort12 read;
Consulta OK, 0 filas afectadas (0.01 seg)
2017-08-03T21:08:27.267947Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T21:08:27.267979Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T21:08:27.268009Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T21:08:27.268040Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T21:08:27.268070Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T21:08:27.268113Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_SHARED_READ_ONLY(SRO) 
2017-08-03T21:08:27.268145Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T21:08:27.268175Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

10, MDL_SHARED_NO_READ_WRITE(SNRW)

Usado para la declaración LOCK TABLES WRITE

Compatibilidad:

    Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNRW | +  +  -  -  -  -  -  -  -  - |

Se puede ver que DML(SW) y SELECT(SR) están bloqueados, solo SH funciona bien, y también DESC(SH) .

mysql> lock table testsort12 write;
Consulta OK, 0 filas afectadas (0.00 seg)
2017-08-03T21:13:07.113347Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T21:13:07.113407Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T21:13:07.113435Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:GLOBAL 
2017-08-03T21:13:07.113458Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T21:13:07.113482Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113505Z 3 [Nota] (------>MDL PRINT) Duración del MDL es:MDL_STATEMENT 
2017-08-03T21:13:07.113604Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T21:13:07.113637Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T21:13:07.113660Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T21:13:07.113681Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T21:13:07.113703Z 3 [Nota] (-->MDL PRINT) Nombre del objeto es: 
2017-08-03T21:13:07.113725Z 3 [Nota] (--->MDL PRINT) Espacio de nombres es:SCHEMA 
2017-08-03T21:13:07.113746Z 3 [Nota] (---->MDL PRINT) Ruta rápida es:(Sí)
2017-08-03T21:13:07.113768Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113791Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T21:13:07.113813Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 
2017-08-03T21:13:07.113842Z 3 [Nota] (acquire_lock)¡Este MDL LOCK se adquirió con éxito!
2017-08-03T21:13:07.113865Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T21:13:07.113887Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T21:13:07.113922Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T21:13:07.113945Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T21:13:07.113975Z 3 [Nota] (----->MDL PRINT) El tipo de MDL es:MDL_SHARED_NO_READ_WRITE(SNRW) 
2017-08-03T21:13:07.113998Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T21:13:07.114021Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Además, lock table necesita IX de LOCK y SCHEMA, en otras palabras, flush tables with read lock; bloqueará
lock table testsort12 write; pero lock table testsort12 read pero no bloquea.

11、MDL_EXCLUSIVE(X)

para varias operaciones DDL, el comentario es CREATE/DROP/operación RENAME TABLE, en realidad, prácticamente todos los DDL involucran este bloqueo, como se analizó
operación add column, pero generalmente tiene una duración relativamente breve.

Compatibilidad:

   Solicitud | Solicitudes de bloqueo concedidas         |
    tipo  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   X     | -  -  -  -  -  -  -  -  -  - |

no hay bloqueo inesperado en la parte superior, y también está bloqueado por todo

por ejemplo, la operación add column recién mencionada

2017-08-03T19:46:54.804240Z 3 [Nota] (>MDL PRINT) El id de hilo es 3: 
2017-08-03T19:46:54.804254Z 3 [Nota] (->MDL PRINT) El nombre de la base de datos es:test 
2017-08-03T19:46:54.804267Z 3 [Nota] (-->MDL PRINT) El nombre del objeto es:testsort12 
2017-08-03T19:46:54.804280Z 3 [Nota] (--->MDL PRINT) El espacio de nombres es:TABLA 
2017-08-03T19:46:54.804293Z 3 [Nota] (----->MDL PRINT) El tipo de Mdl es:MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.804306Z 3 [Nota] (------>MDL PRINT) La duración de Mdl es:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Nota] (------->MDL PRINT) El estado de Mdl es:VACÍO 

Seis, comentarios de código fuente

enum enum_mdl_type {
 /*
  un bloqueo de metadatos exclusivo de intención. Utilizado solo para bloqueos en ámbito.
  El propietario de este tipo de bloqueo puede obtener bloqueos exclusivos actualizables
  objetos individuales.
  Compatible con otros bloqueos IX, pero incompatibles con S y
  bloqueos X.
 */
 MDL_INTENTION_EXCLUSIVE= 0,
 /*
  un bloqueo de metadatos compartido.
  para usar en casos en los que solo estamos interesados en los metadatos del objeto
  no hay intención de acceder a los datos del objeto (por ejemplo, para almacenar
  rutinas o durante la preparación de declaraciones preparadas).
  también nos confundimos-usar este tipo de bloqueo para abrir MANEJADORES, ya que el bloqueo
  adquirido por esta declaración debe ser compatible con el bloqueo adquirido
  mediante la declaración LOCK TABLES ... ESCRIBIR, es decir, SNRW (No podemos evitarlo simplemente
  de adquirir un bloqueo S en el tiempo de APERTURA ... MANEJADOR y actualizarlo a SR
  bloqueo para MANEJADOR ... LECTURA ya que no resuelve el problema con la necesidad
  para abortar las declaraciones DML que esperan en el bloqueo de nivel de tabla mientras tienen
  abrir MANEJADOR en la misma conexión).
  para evitar el bloqueo muerto que puede ocurrir cuando el bloqueo SNRW se está actualizando a
  bloqueo X para la tabla en la que hay un bloqueo S activo que es poseído por
  hilo que espera a su vez en la tabla-nivel de bloqueo poseído por el hilo
  realizar la actualización debemos usar thr_abort_locks_for_thread()
  instalación en tal situación.
  este problema no se produce para los bloqueos en rutinas almacenadas ya que no
  usar bloqueos SNRW para ellos. tampoco se produce cuando se usan bloqueos S
  durante las llamadas PREPARE como tabla-nivel de bloqueos no se adquieren en este
  caso.
 */
 MDL_SHARED,
 /*
  Un bloqueo de metadatos compartidos con alta prioridad.
  Usado para casos en los que no hay intención de acceder a los datos del objeto (es decir,
  datos en la tabla).
  "Prioridad alta" significa que, a diferencia de otros bloqueos compartidos, se otorga
  ignorando solicitudes pendientes de bloqueos exclusivos. Pensado para uso en
  casos en los que solo necesitamos acceder a metadatos y no a datos, por ejemplo, cuando
  llenando una tabla INFORMATION_SCHEMA.
  Dado que el bloqueo SH es compatible con el bloqueo SNRW, la conexión que
  posee el bloqueo SH no debe intentar adquirir ningún tipo de tabla-nivel
  o fila-nivel de bloqueo, ya que esto puede llevar a un bloqueo. Además, después
  adquirir el bloqueo SH, la conexión no debe esperar ningún otro
  recurso, ya que podría causar hambruna para bloqueos X y un posible
  bloqueo durante la actualización de SNW o SNRW a bloqueo X (por ejemplo, si la
  La actualización de conexión mantiene los recursos que se están esperando).
 */
 MDL_SHARED_HIGH_PRIO,
 /*
  Un bloqueo de metadatos compartido para casos en los que hay la intención de leer datos
  de la tabla.
  Una conexión que mantiene este tipo de bloqueo puede leer la metadatos de la tabla y leer
  datos de la tabla (después de adquirir el bloqueo apropiado de tabla y fila-niveles de bloqueo).
  Esto significa que solo se puede adquirir TL_READ, TL_READ_NO_INSERT, y
  tabla similar-niveles de bloqueo en la tabla si uno mantiene un bloqueo SR MDL en la misma.
  Para ser utilizado para tablas en SELECTs, subconsultas y LOCK TABLE ... READ
  sentencias.
 */
 MDL_SHARED_READ,
 /*
  Un bloqueo de metadatos compartido para casos en los que hay la intención de modificar
  (y no solo leer) datos en la tabla.
  Una conexión que mantiene un bloqueo SW puede leer la metadatos de la tabla y modificar o leer
  datos de la tabla (después de adquirir el bloqueo apropiado de tabla y fila-niveles de bloqueo).
  Para ser utilizado para tablas que sean modificadas por INSERT, UPDATE, DELETE
  sentencias, pero no LOCK TABLE ... WRITE o DDL). También tomado por
  SELECT ... FOR UPDATE.
 */
 MDL_SHARED_WRITE,
 /*
  Una versión del bloqueo MDL_SHARED_WRITE con prioridad menor que
  bloqueos MDL_SHARED_READ_ONLY. Usados por sentencias DML que modifican
  tablas y utilizando la cláusula LOW_PRIORITY.
 */
 MDL_ESCRIBIR_BAJA_PRIORIDAD,
 /*
  Un bloqueo de metadatos compartido y actualizable que permite actualizaciones concurrentes y
  lecturas de datos de la tabla.
  Una conexión que mantiene este tipo de bloqueo puede leer la metadatos de la tabla y leer
  datos de la tabla. No debe modificar datos ya que este bloqueo es compatible con
  bloqueos SRO.
  Puede ser actualizado a SNW, SNRW y bloqueos X. Una vez que el bloqueo SU se actualiza a X
  o la modificación de datos con bloqueo SNRW puede ocurrir libremente.
  Para usar en la primera fase de ALTER TABLE.
 */
 MDL_LEER_ACTUALIZABLE,
 /*
  Un bloqueo de metadatos compartido para los casos en los que necesitamos leer datos de la tabla
  y bloquear todas las modificaciones concurrentes en él (tanto datos como metadatos).
  Usado por la declaración LOCK TABLES READ.
 */
 MDL_LEER_SÓLO_COMPARTIDO,
 /*
  Un bloqueo de metadatos compartido y actualizable que bloquea todos los intentos de actualizar
  datos de la tabla, permitiendo lecturas.
  Una conexión que mantiene este tipo de bloqueo puede leer la metadatos de la tabla y leer
  datos de la tabla.
  Se puede actualizar a un bloqueo de metadatos X.
  Nota, que este tipo de bloqueo no es compatible con SNRW o SW
  tipos de bloqueo, adquiriendo el motor adecuado-bucleos de nivel para la lectura
  (TL_LEER* para MyISAM, los bloqueos de fila compartidos en InnoDB) deben ser
  concurrencia-libre.
  Para ser utilizado en la primera fase de ALTER TABLE, cuando se copian datos entre
  tablas, permitiendo SELECTs concurrentes desde la tabla, pero no UPDATEs.
 */
 MDL_SHARED_NO_WRITE,
 /*
  Un bloqueo de metadatos compartido actualizable que permite a otras conexiones
  acceder a los metadatos de la tabla, pero no a los datos.
  Bloquea todos los intentos de leer o actualizar los datos de la tabla, permitiendo
  consultas INFORMATION_SCHEMA y SHOW.
  Una conexión que mantiene este tipo de bloqueo puede leer los metadatos de la tabla modificar y
  leer datos de la tabla.
  Se puede actualizar a un bloqueo de metadatos X.
  Para ser utilizado para la declaración LOCK TABLES WRITE.
  No es compatible con ningún otro tipo de bloqueo salvo S y SH.
 */
 MDL_SHARED_NO_READ_WRITE,
 /*
  Un bloqueo de metadatos exclusivo.
  Una conexión que mantiene este bloqueo puede modificar tanto los metadatos como los datos de la tabla.
  No se puede conceder otro tipo de bloqueo de metadatos mientras se mantiene este bloqueo.
  Para ser utilizado para CREATE/DROP/declaraciones RENAME TABLE y para la ejecución de
  fases determinadas de otras declaraciones DDL.
 */
 MDL_EXCLUSIVE,
 /* Esto debería ser el último !!! */
 MDL_TYPE_END};
/** Duración del bloqueo de metadatos. */
enum enum_mdl_duration {
 /**
  Los bloqueos con duración de sentencia se liberan automáticamente al final
  de la sentencia o transacción.
 */
 MDL_STATEMENT= 0,
 /**
  Los bloqueos con duración de transacción se liberan automáticamente al final
  de la transacción.
 */
 MDL_TRANSACTION,
 /**
  Los bloqueos con duración explícita sobreviven al final de la sentencia y la transacción.
  Tienen que ser liberados explícitamente llamando a MDL_context::release_lock().
 */
 MDL_EXPLICIT,
 /* ¡Este debería ser el último! */
 MDL_DURATION_END };
/**
  Nombres de espacio de objetos.
  Sic: al agregar un nuevo miembro a este enum, asegúrate de
  Actualizar el array m_namespace_to_wait_state_name en mdl.
  Existen diferentes tipos de objetos en diferentes nombres de espacio.
   - GLOBAL se utiliza para el bloqueo de lectura global.
   - TABLESPACE es para tablespaces.
   - SCHEMA es para esquemas (también conocido como bases de datos).
   - TABLE es para tablas y vistas.
   - FUNCTION es para funciones almacenadas.
   - PROCEDURE es para procedimientos almacenados.
   - TRIGGER es para disparadores.
   - EVENT es para eventos del planificador de eventos.
   - COMMIT es para habilitar el bloqueo de lectura global para bloquear los compromisos.
   - USER_LEVEL_LOCK es para el usuario-nivel de bloqueo.
   - LOCKING_SERVICE es para el complemento de nombre RW-servicio de bloqueo
  Note que aunque no hay bloqueo de metadatos en los desencadenadores,
  es necesario tener un espacio de nombres separado para ellos ya que
  MDL_key también se utiliza fuera del subsistema MDL.
  También nota que las solicitudes esperando para el usuario-los bloqueos de nivel reciben un trato especial
  tratamiento - la espera se aborta si se pierde la conexión con el cliente.
 */
 enum enum_mdl_namespace { GLOBAL=0,
              TABLESPACE,
              SCHEMA,
              TABLE,
              FUNCTION,
              PROCEDURE,
              TRIGGER,
              EVENT,
              COMMIT,
              USER_LEVEL_LOCK,
              LOCKING_SERVICE,
              BACKUP,
              BINLOG,
              /* ¡Este debería ser el último! */
              NAMESPACE_END };
Te gustará