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

Analisi del problema del MDL LOCK (MDL LOCK) del METADATA LOCK in MYSQL

I. Introduction

MDL lock in MYSQL has always been a problem that is quite troublesome, when we talk about locks, we tend to prefer gap lock, next key lock, row lock, etc. under the INNODB lower level, because it is easy to understand and observe, but for MDL LOCK, we know very little, because it is not easy to observe, and can only be seen by checking show processlist when there is a problem

The simple so-called 'Waiting for table metadata lock' status, in fact, MDL LOCK is a very complex subsystem at the upper level of MYSQL, with its own deadlock detection mechanism

(Undirected graph?) And what everyone usually calls 'lock table' actually refers to it, which shows its importance and severity. The author has also learned some (tip of the iceberg) according to their own needs without being able to read all the code, but the author has made it easier to learn and study by adding a TICKET print function to print the MDL LOCK locking process of the statement. Below, we will start with some basics and then tell you what has been modified, and finally test and analyze each MDL TYPE. If you are not interested in basic concepts and the added print function, you can directly refer to the fifth part of the locking test. However, if you do not understand the basic knowledge, it may be a bit difficult to understand.

Just recently encountered a situation where MDL LOCK caused deadlock, a case will be given in the next article, here we only look at the theory

----Level: MYSQL SERVER level, in fact, MDL LOCK starts to acquire as early as in the open_table function, which can be said to be the earliest acquired LOCK structure

----Earliest acquisition stage: THD::enter_stage: 'Opening tables'

Call stack frame

#0 open_table_get_mdl_lock (thd=0x7fffd0000df0, ot_ctx=0x7fffec06fb00, 
  table_list=0x7fffd00067d8, flags=0, mdl_ticket=0x7fffec06f950)
  在/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_base.cc:2789
#1 0x0000000001516e17 in open_table (thd=0x7fffd0000df0, 
  table_list=0x7fffd00067d8, ot_ctx=0x7fffec06fb00)
  在/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 è utilizzato per il blocco di lettura globale.

- TABLESPACE è per gli spazi di archiviazione.

- SCHEMA è per gli schemi (noto anche come database).

- TABLE è per le tabelle e le viste.

- FUNCTION è per le funzioni memorizzate.

- PROCEDURE è per le procedure memorizzate.

- TRIGGER è per i trigger.

- EVENT è per gli eventi del pianificatore degli eventi.

- COMMIT serve a attivare il blocco di lettura globale per i commit.

- USER_LEVEL_LOCK è per i lock a livello utente.

- LOCKING_SERVICE è per il servizio di lock RW del plugin di nome

3、实现分类

scope lock: generally corresponds to global MDL LOCK, such as flush table with read lock for namespace space:GLOBAL type:S

object lock: as the name implies, object-level MDL LOCK, such as TABLE

Below are the comments in the source code:

 /**
  Helper struct which defines how different types of locks are handled
  for a specific MDL_lock. In practice we use only two strategies: "scoped"
  lock strategy for locks in GLOBAL, COMMIT, TABLESPACE and SCHEMA namespaces
  and "object" lock strategy for all other namespaces.
 */

4、MDL compatibility matrix

scope lock:
     | Type of active  |
 Request |  scoped lock  |
  type  | IS(*) IX  S X |
 ---------+------------------+
 IS    | +   +  + + |
 IX    | +   +  - - |
 S    | +   -  + - |
 X    | +   -  - - |
object lock:
    Request | Granted requests for lock      |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   S     | +  +  +  +  +  +  +  +  +  - |
   SH    | +  +  +  +  +  +  +  +  +  - |
   SR    | +  +  +  +  +  +  +  +  -  - |
   SW    | +  +  +  +  +  +  -  -  -  - |
   SWLP   | +  +  +  +  +  +  -  -  -  - |
   SU    | +  +  +  +  +  -  +  -  -  - |
   SRO    | +  +  +  -  -  +  +  +  -  - |
   SNW    | +  +  +  -  -  -  +  -  -  - |
   SNRW   | +  +  -  -  -  -  -  -  -  - |
   X     | -  -  -  -  -  -  -  -  -  - |

5、MDL duration and when MDL lasts

This does not require much explanation, just check the source code comments

MDL_STATEMENT: Locks with statement duration are automatically released at the end
       dello statement o della transazione.
MDL_TRANSACTION: Locks with transaction duration are automatically released at the end
        of transaction
MDL_EXPLICIT: I lock con durata esplicita sopravvivono alla fine dello statement e della transazione.
       Devono essere rilasciati esplicitamente chiamando MDL_context::release_lock().

6, PERCORSO RAPIDO MDL LOCK (intrusivo) O PERCORSO SLOW (obtrusivo)

L'uso di due metodi diversi ha lo scopo di ottimizzare l'implementazione di MDL lock, di seguito è il commento del codice sorgente

A) Tipi di lock "intrusivo"
      1) Ogni tipo dell'insieme dovrebbe essere compatibile con tutti gli altri
        tipi dell'insieme (incluso se stesso).
      2) Questi tipi dovrebbero essere comuni per le operazioni DML
     Il nostro obiettivo è ottimizzare l'acquisizione e la liberazione dei lock di questo
     evitando controlli e manipolazioni complessi su m_waiting/
     m_granted bitmaps/lists. Li sostituiamo con un controllo di e
     incremento/decremento dei contatori interi.
     Chiamiamo questo tipo di acquisizione/liberazione "percorso rapido".
     L'uso del "percorso rapido" riduce la dimensione del sezione critica associata
     con il lock MDL_lock::m_rwlock nel caso comune e di conseguenza aumenta
     scalabilità.
     L'importo di acquisizione/liberazione di un tipo specifico
     "intrusivo" lock aumenta/decrementsa il contatore compresso in
     MDL_lock::m_fast_path_state è restituito da questa funzione.
B) tipi di lock "obtrusive"
      1) Il lock concesso o in attesa di quei tipo è incompatibile con
        alcuni altri tipi di lock o con se stesso.
      2) Non comune per operazioni DML
     Questi lock devono essere sempre acquisiti coinvolgendo manipolazioni su
     m_waiting/m_granted bitmaps/lists, ovvero dobbiamo utilizzare il "path lento"
     ciò. Inoltre, in presenza di lock attivi/pendenti da
     Dobbiamo acquisire anche i lock di tipo "obtrusive" utilizzando il "path lento", anche se
     tipo "unobtrusive".

7, classe MDL_request

Ossia la necessità di ottenere MDL LOCK dopo l'analisi della frase, quindi attraverso questo oggetto di classe nell'子系统 MDL
Viene effettuata una richiesta di MDL LOCK, che include approssimativamente i seguenti attributi

/** Tipo di lock di metadati. */
 enum enum_mdl_type type; //Tipo richiesto
 /** Durata della lock richiesta. */
 enum enum_mdl_duration duration; //Durata
 /**
  Puntatori per partecipare alla lista delle richieste di blocco per questo contesto.
 */
 MDL_request *next_in_list; //Implementazione a elenco bidirezionale
 MDL_request **prev_in_list;
 /**
  Puntatore all'oggetto ticket di lock per questa richiesta di lock.
  Valido solo se questa richiesta di lock è soddisfatta.
 */
 MDL_ticket *ticket; //Attenzione: se la richiesta è riuscita (senza attesa), punta a un TICKET reale, altrimenti è NULL
 /** Una lock è richiesta in base a un nome qualificato completo e tipo. */
 MDL_key key; // Attenzione, è un tipo MDL_KEY, che è principalmente il	Namespace+DB+OBJECT_NAME descritto prima

Classe MDL_key, che è il Namespace+DB+OBJECT_NAME reale, tutto messo in un array di char, sarà presente in MDL_LOCK e MDL_REQUEST

private:

uint16 m_length;

uint16 m_db_name_length;

char m_ptr[MAX_MDLKEY_LENGTH]; // È stato messo qui

8, MDL_ticket

Come il biglietto, se si ottiene MDL LOCK, viene restituito un biglietto a MDL_request, se in attesa non sorgono codici MDL_context::acquire_lock

Ovviamente, questo è anche il tipo di classe che ho osservato principalmente

/**
  Puntatori per partecipare alla lista delle richieste di blocco per questo contesto.
  Contesto privato. Come spiegato, qui è la formazione della lista di liste nel contesto, che è privato della thread
 */
 MDL_ticket *next_in_context;
 MDL_ticket **prev_in_context;
 /**
  Puntatori per partecipare alla lista delle richieste soddisfatte/pendenti
  per il blocco. Accessibile esternamente. Come spiegato, qui è la formazione della lista di liste MDL_LOCK, che è globale
 */
 MDL_ticket *next_in_lock;
 MDL_ticket **prev_in_lock;
/**
  Contesto del proprietario del ticket di blocco sui metadati. Accessibile esternamente.
  Evidentemente qui si punta al proprietario del ticket, ossia MDL_context, che è un attributo della thread
 */
 MDL_context *m_ctx; 
 /**
  Puntatore all'oggetto di blocco per questo biglietto di blocco. Accessibile esternamente.
  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 in
  Instead of MDL_lock::m_granted bitmap/list, it 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 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 smaller
 */
 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

Every 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, I provide 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;

10, MDL_context

Questo è un cosiddetto contesto di scambio tra l'intero thread MYSQL e il sottosistema di blocco MDL, che contiene molti metodi e attributi, gli attributi che mi interessano di più sono i seguenti:

/**
  Se la nostra richiesta di un blocco è programmata o annullata dal blocco mortale
  detector, il risultato è registrato in questa classe.
 */
 MDL_wait m_wait;
/**
  Liste di tutti i ticket MDL acquisiti da questa connessione.
  Questo è un array di liste di durata diversa dei blocchi MDL. In realtà è
  MDL_STATEMENT una lista
  MDL_TRANSACTION una lista
  MDL_EXPLICIT una lista
 */
Ticket_list m_tickets[MDL_DURATION_END];
//Questo è un puntatore di classe padre che punta a un oggetto figlio, un esempio tipico di sovrascrittura di funzioni virtuali, in realtà punta a un thread
/*
class THD :public MDL_context_owner,
      public Query_arena,
      public Open_tables_state
*/
MDL_context_owner *m_owner;

11, MDL_wait

Questa classe rappresenta lo stato di acquisizione del ticket corrente

enum_wait_status m_wait_status;

contenente

EMPTY inizializzazione

GRANTED ottenuto con successo

VICTIM blocco mortale

TIMEOUT tempo scaduto

KILLED KILLED

12, in attesa del segnale

PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
{
 {0, "In attesa del blocco di lettura globale", 0},
 {0, "In attesa del blocco dei metadati dello spazio dei dati", 0},
 {0, "In attesa del blocco dei metadati dello schema", 0},
 {0, "In attesa del blocco dei metadati della tabella", 0},
 {0, "Waiting for stored function metadata lock", 0}
 {0, "Waiting for stored procedure metadata lock", 0},
 {0, "Waiting for trigger metadata lock", 0},
 {0, "Waiting for event metadata lock", 0},
 {0, "Waiting for commit lock", 0},
 {0, "User lock", 0}, /* Compatibile con lo stato vecchio. */
 {0, "Waiting for locking service lock", 0},
 {0, "Waiting for backup lock", 0},
 {0, "Waiting for binlog lock", 0}
};

3. Aggiungere la funzione di stampa MDL LOCK

Il modo migliore per studiare MDL LOCK lock è ottenere il flusso di locking, upgrading e downgrading di MDL, poiché il codice sorgente è troppo grande e non è possibile coprire tutto
Anche se la versione 5.7 ha aggiunto

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

Il modo per visualizzare MDL LOCK è tramite questo metodo, ma se si desidera osservare quali MDL LOCK vengono effettivamente acquisiti da una certa istruzione, sembra essere inadeguato. Quindi, l'autore ha aggiunto una funzione原型in mdl.cc come segue

/*p_ticket in parameter*/

int my_print_ticket(const MDL_ticket* p_ticket)

Ecco aggiunto questo原型函数 come funzione amica in mdl_ticket, altrimenti non è possibile accedere ai membri privati, mentre i metodi pubblici forniti sono piuttosto complessi

friend int my_print_ticket(const MDL_ticket* p_ticket);

Le informazioni principali del MDL LOCK vengono prese e stampate nel log di errore mysql:

L'ID della thread può essere ottenuto tramite p_ticket->m_ctx->get_thd();

Il nome del database del lock mdl può essere ottenuto tramite p_ticket->m_lock->key.db_name()

Il nome dell'oggetto del lock mdl può essere ottenuto tramite p_ticket->m_lock->key.name()

Lo spazio dei nomi del lock mdl può essere ottenuto tramite p_ticket->m_lock->key.mdl_namespace()

Il percorso rapido del lock mdl può essere ottenuto tramite p_ticket->m_is_fast_path e viene outputto se è vero, altrimenti non viene outputto

Il tipo del lock mdl può essere ottenuto tramite p_ticket->m_type

La durata del lock mdl può essere ottenuta tramite p_ticket->m_duration

Le informazioni di output sono come segue:

2017-08-03T07:34:21.720583Z 3 [Note] (>MDL PRINT) L'ID della thread è 3:

2017-08-03T07:34:21.720601Z 3 [Note] (->MDL PRINT) Il nome del database è: test

2017-08-03T07:34:21.720619Z 3 [Note] (-->MDL PRINT) Il nome dell'oggetto è: test

2017-08-03T07:34:21.720637Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è: TABLE

2017-08-03T07:34:21.720655Z 3 [Note] (---->MDL PRINT) Il percorso rapido è: (Y)

2017-08-03T07:34:21.720673Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_SHARED_WRITE(SW)

2017-08-03T07:34:21.720692Z 3 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_TRANSACTION

In realtà è simile alle informazioni di metadata_locks, questo è il mio Thread id, che è il risultato di show processlist, ma posso ottenere informazioni storiche sulla acquisizione del lock, qui non ho LOCK_STATUS: GRANTED, ma posso determinarlo logicamente nella logica di MDL_context::acquire_lock

mysql> select * from performance_schema.metadata_locks\G
*************************** 1. riga ***************************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: test
OBJECT_NAME: test
OBJECT_INSTANCE_BEGIN: 140734412907760
LOCK_TYPE: SHARED_WRITE
LOCK_DURATION: TRANSACTION
LOCK_STATUS: GRANTED
SOURCE: sql_parse.cc:6314
OWNER_THREAD_ID: 39
OWNER_EVENT_ID: 241

4, aggiungere funzioni di stampa appropriate in posizioni adeguate per osservare

Poiché dobbiamo studiare il locking, upgrading e downgrading di MDL LOCK, dobbiamo necessariamente trovare l'ingresso delle loro funzioni, quindi aggiungere funzioni di stampa appropriate in posizioni adeguate per osservare, di seguito sono indicati i punti di stampa, la maggior parte del codice sorgente è stata eliminata, si prega di consultare il codice sorgente di riferimento

1、Locking: MDL_context::acquire_lock

bool
MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
{
 if (mdl_request->ticket) // Ottenimento del ticket con successo
 {
  /*
   siamo riusciti ad ottenere il blocco senza aspettare.
   MDL_lock, MDL_context e MDL_request sono stati aggiornati
   di conseguenza, possiamo semplicemente restituire successo.
  */
  //REQUESET获取TICKET成功 此处打印
  return FALSE;
 }
 /*
  Our attempt to acquire lock without waiting has failed.
  As a result of this attempt we got MDL_ticket with m_lock
  member pointing to the corresponding MDL_lock object which
  has MDL_lock::m_rwlock write-locked.
 */
 //获取不成功加入MDL_lock 等待队列
 lock= ticket->m_lock;
 lock->m_waiting.add_ticket(ticket);
 will_wait_for(ticket); //死锁检测
 /* There is a shared or exclusive lock on the object. */
 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
 find_deadlock(); 
 //此处打印TICKET进入了等待流程
 if (lock->needs_notification(ticket) || lock->needs_connection_check())
 {
  }
 done_waiting_for();//等待完成对死锁检测等待图进行调整去掉本等待边edge(无向图)
 //当然到这里也是通过等待后获得成功了状态为GRANTED
 DBUG_ASSERT(wait_status == 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)
{
 /* Solo permettere il degrado da EXCLUSIVE e 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);//构造一个request
 //此处打印出来的TICKET类型 
 if (acquire_lock(&mdl_new_lock_request, lock_wait_timeout)) //尝试使用新的LOCK_TYPE进行加锁
  DBUG_RETURN(TRUE);
 is_new_ticket= ! has_lock(mdl_svp, mdl_new_lock_request.ticket);
 lock= mdl_ticket->m_lock;
 //Below is a series of maintenance operations for MDL_LOCK and so-called merge operations
 /* Code below assumes that we were upgrading to "obtrusive" type of lock. */
 DBUG_ASSERT(lock->is_obtrusive_lock(new_type));
 /* Merge the acquired and the original lock. @todo: move to a method. */
 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);
 }
 //Questa è la stampa del tipo di TICKET aggiornato 
 DBUG_RETURN(FALSE);
}

Certo, al momento ho solo stampato in questi punti, in futuro, se è necessario aggiungere in altri punti, è sufficiente aggiungere una funzione.

V, test di bloccaggio di vari MDL LOCK TYPE

1、MDL_INTENTION_EXCLUSIVE(IX)

Questo blocco di lock apparirà in molte operazioni, ad esempio, eseguire qualsiasi operazione DML/DDL attiverà, in effetti, le operazioni DML come DELETE/UPDATE/INSERT/FOR UPDATE aggiungeranno un lock IX globale prima di aggiungere un lock a questo oggetto, le istruzioni DDL almeno aggiungeranno un lock IX globale, un lock IX sullo SCHEMA dell'oggetto e un lock su questo oggetto. Di seguito è riportato l'esempio di lock GLOABL IX MDL attivato da DELETE:

2017-08-03T18:22:38.092100Z 3 [Note] Test2:open_tables_for_query()
2017-08-03T18:22:38.092205Z 3 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T18:22:38.092242Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T18:22:38.092276Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è: GLOBAL 
2017-08-03T18:22:38.092310Z 3 [Note] (---->MDL PRINT) Il percorso rapido è: (Y)
2017-08-03T18:22:38.092344Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:22:38.092380Z 3 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_STATEMENT 
2017-08-03T18:22:38.092551Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è: EMPTY 

Di seguito sono riportati il GLOABL IX MDL LOCK attivato dalla statement ALETER e il MDL LOCK di livello SCHEMA

2017-08-03T18:46:05.894871Z 3 [Note] (acquire_lock) L'acquisizione di questo MDL LOCK è andata a buon fine!
2017-08-03T18:46:05.894915Z 3 [Note] (>MDL PRINT) L'ID del thread è 3: 
2017-08-03T18:46:05.894948Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è: GLOBAL 
2017-08-03T18:46:05.894980Z 3 [Note] (---->MDL PRINT) Il percorso rapido è: (Y)
2017-08-03T18:46:05.895012Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895044Z 3 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_STATEMENT 
2017-08-03T18:46:05.895076Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 
2017-08-03T18:46:05.895116Z 3 [Note] (acquire_lock)Acquisizione di questo MDL LOCK riuscita!
2017-08-03T18:46:05.895147Z 3 [Note] (>MDL PRINT) L'ID del thread è 3: 
2017-08-03T18:46:05.895206Z 3 [Note] (->MDL PRINT) Il nome del database è:test 
2017-08-03T18:46:05.895243Z 3 [Note] (-->MDL PRINT) Il nome dell'oggetto è: 
2017-08-03T18:46:05.895276Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è:SCHEMA 
2017-08-03T18:46:05.895325Z 3 [Note] (---->MDL PRINT) Il percorso rapido è:(Y)
2017-08-03T18:46:05.895357Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895390Z 3 [Note] (------>MDL PRINT) La durata di Mdl è:MDL_TRANSACTION 
2017-08-03T18:46:05.895421Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 

Quindi questo MDL LOCK è ovunque, e solo il problema della compatibilità, se non compatibile, si blocca. La tipologia di IX di SCOPED è generalmente compatibile, a meno che non si incontri
Tipo S

2、MDL_SHARED(S)

Questo blocco viene utilizzato generalmente in flush tables with read lock

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.01 sec)
2017-08-03T18:19:11.603911Z 3 [Note] (acquire_lock)Acquisizione del LOCK MDL THIS avvenuta con successo!
2017-08-03T18:19:11.603947Z 3 [Note] (>MDL PRINT) L'id della thread è 3: 
2017-08-03T18:19:11.603971Z 3 [Note] (--->MDL PRINT) Il namespace è:GLOBAL 
2017-08-03T18:19:11.603994Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è:MDL_SHARED(S) 
2017-08-03T18:19:11.604045Z 3 [Note] (------>MDL PRINT) La durata di Mdl è:MDL_EXPLICIT 
2017-08-03T18:19:11.604073Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 
2017-08-03T18:19:11.604133Z 3 [Note] (acquire_lock)Acquisizione del LOCK MDL THIS avvenuta con successo!
2017-08-03T18:19:11.604156Z 3 [Note] (>MDL PRINT) L'id della thread è 3: 
2017-08-03T18:19:11.604194Z 3 [Note] (--->MDL PRINT) Il namespace è:COMMIT 
2017-08-03T18:19:11.604217Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è:MDL_SHARED(S) 
2017-08-03T18:19:11.604240Z 3 [Note] (------>MDL PRINT) La durata di Mdl è:MDL_EXPLICIT 
2017-08-03T18:19:11.604310Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 

Notiamo che il suo namspace è GLOBAL e COMMIT, quindi evidentemente sono LOCK SCOPED, il loro TYPE è S, quindi è chiaro che secondo il principio di compatibilità
L'incompatibilità tra MDL IX SCOPED e MDL S, flush tables with read lock; bloccerà tutte le operazioni DELETE/UPDATE/INSERT/FOR UPDATE
e operazioni DML e DDL (poiché queste operazioni richiedono un blocco MDL IX globale)

3、MDL_SHARED_HIGH_PRIO(SH)

Questo blocco è utilizzato molto spesso, ma non se ne percepisce l'uso, ad esempio durante operazioni desc

Compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SH    | +  +  +  +  +  +  +  +  +  - |
mysql> desc test.testsort10;
2017-08-03T19:06:05.843277Z 4 [Note] (acquire_lock) L'acquisizione di questo blocco MDL è andata a buon fine!
2017-08-03T19:06:05.843324Z 4 [Note] (>MDL PRINT) L'ID del thread è 4: 
2017-08-03T19:06:05.843359Z 4 [Note] (->MDL PRINT) Il nome del database è: test 
2017-08-03T19:06:05.843392Z 4 [Note] (-->MDL PRINT) Il nome dell'oggetto è: testsort10 
2017-08-03T19:06:05.843425Z 4 [Note] (--->MDL PRINT) Lo spazio dei nomi è: TABLE 
2017-08-03T19:06:05.843456Z 4 [Note] (---->MDL PRINT) Il percorso rapido è: (Sì)
2017-08-03T19:06:05.843506Z 4 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_SHARED_HIGH_PRIO(SH) 
2017-08-03T19:06:05.843538Z 4 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_TRANSACTION 
2017-08-03T19:06:05.843570Z 4 [Note] (------->MDL PRINT) Lo stato di Mdl è: VUOTO 

Questo tipo di lock ha una priorità più alta, ma non è compatibile con X. È anche facile da capire, ad esempio, non è possibile eseguire l'operazione desc in fase di rename.

4、MDL_SHARED_READ(SR)

Questo tipo di lock viene generalmente utilizzato nei select non legati alla lettura corrente, compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | 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 [Note] (acquire_lock)L'acquisizione di questa lock MDL è andata a buon fine!
2017-08-03T19:13:52.338813Z 4 [Note] (>MDL PRINT) L'ID del thread è 4: 
2017-08-03T19:13:52.338847Z 4 [Note] (->MDL PRINT) Il nome del database è:test 
2017-08-03T19:13:52.338883Z 4 [Note] (-->MDL PRINT) Il nome dell'oggetto è:testsort10 
2017-08-03T19:13:52.338917Z 4 [Note] (--->MDL PRINT) Lo spazio dei nomi è:TABLE 
2017-08-03T19:13:52.338950Z 4 [Note] (---->MDL PRINT) Il percorso rapido è:(Y)
2017-08-03T19:13:52.339025Z 4 [Note] (----->MDL PRINT) Il tipo di Mdl è:MDL_SHARED_READ(SR) 
2017-08-03T19:13:52.339062Z 4 [Note] (------>MDL PRINT) La durata di Mdl è:MDL_TRANSACTION 
2017-08-03T19:13:52.339097Z 4 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 

Ecco che dobbiamo menzionare anche la situazione in cui a volte select si blocca (ad esempio, in una fase di DDL è necessaria la lock MDL X). Non possiamo far altro che lamentarci
MySQL blocca effettivamente la select, qui è il problema di incompatibilità tra il blocco X e SR dell'oggetto mdl (vedere la matrice di compatibilità precedente).

5, MDL_SHARED_WRITE(SW)

Questa chiave viene generalmente utilizzata per bloccare la tabella durante operazioni DELETE/UPDATE/INSERT/FOR UPDATE ecc. (lettura corrente), non include operazioni DDL
Ma attenzione, le operazioni DML hanno effettivamente un blocco IX globale, come già menzionato, questa chiave è solo sull'oggetto

Compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | 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 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:25:41.218461Z 4 [Note] (>MDL PRINT) Thread id is 4: 
2017-08-03T19:25:41.218493Z 4 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T19:25:41.218525Z 4 [Note] (-->MDL PRINT) OBJ_name is:testsort10 
2017-08-03T19:25:41.218557Z 4 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T19:25:41.218588Z 4 [Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T19:25:41.218620Z 4 [Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE(SW) 
2017-08-03T19:25:41.218677Z 4 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T19:25:41.218874Z 4 [Note] (------->MDL PRINT) Mdl status is:EMPTY 

6, MDL_SHARED_WRITE_LOW_PRIO(SWL)

Questo blocco è utilizzato raramente; i commenti di sorgente sono solo

Utilizzato dalle espressioni DML che modificano

tabelle e utilizzando la clausola LOW_PRIORITY

Utilizzato

Compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SWLP   | +  +  +  +  +  +  -  -  -  - |
mysql> update LOW_PRIORITY test.testsort10 set id1=1000 where id1= 96282;
2017-08-03T19:32:47.433507Z 4 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:32:47.433521Z 4 [Note] (>MDL PRINT) Thread id is 4: 
2017-08-03T19:32:47.433533Z 4 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T19:32:47.433547Z 4 [Note] (-->MDL PRINT) OBJ_name is:testsort10 
2017-08-03T19:32:47.433560Z 4 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T19:32:47.433572Z 4 [Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T19:32:47.433594Z 4 [Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE_LOW_PRIO(SWL) 
2017-08-03T19:32:47.433607Z 4 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T19:32:47.433620Z 4 [Note] (------->MDL PRINT) Mdl status is:EMPTY 

7、MDL_SHARED_UPGRADABLE(SU)

Questo lock viene generalmente utilizzato nelle istruzioni ALTER TABLE, può essere aggiornato a SNW, SNRW, X, e contemporaneamente almeno X lock può essere degradato a SU

infatti in INNODB ONLINE DDL è molto dipendente da esso, DML (SW) e SELECT (SR) non bloccano

Compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SU    | +  +  +  +  +  -  +  -  -  - |

abbiamo bisogno di studiare la sua compatibilità, si può vedere che in OBJECT LOCK (SELECT)SR (DML)SW sono permessi, mentre in SCOPED LOCK
Nonostante DML e DDL bloccano sempre GLOBAL, il loro tipo sono tutti IX, quindi questo lock SU non blocca le operazioni di lettura/scrittura DML/SELECT entrare nel livello del motore INNODB, è la base dell'DDL ONLINE, se non è compatibile non puoi entrare nel livello del motore INNODB, tanto meno parlare di DDL ONLINE, attenzione, qui sto dicendo ALGORITHM=INPLACE e non impostare LOCK

(Per operazioni DDL con LOCK=DEFAULT, o con l'omissione della clausola LOCK, MySQL utilizza il livello più basso
di locking disponibile per quel tipo di operazione, permettendo query concorrenti, DML, o entrambi ovunque
possibile. Questo è l'impostazione da utilizzare quando si effettuano cambiamenti pre-pianificati, pre-testati che si sa non
può causare problemi di disponibilità basati sul carico per quella tabella
Quando un'operazione sulla chiave primaria utilizza ALGORITHM=INPLACE, anche se i dati vengono ancora copiati, essa
è più efficiente rispetto all'uso di ALGORITHM=COPY perché:
? Non è richiesto alcun logging di undo o logging di redo associato per ALGORITHM=INPLACE. Queste operazioni aggiungono
sovraccarico per le espressioni DDL che utilizzano ALGORITHM=COPY.
? Le voci degli indici secondari sono pre-sorate e possono essere caricate in ordine.
? Il buffer di cambiamento non viene utilizzato, poiché non ci sono inserimenti random access nei secondari indici.
)

Come segue la seguente espressione

mysql> alter table testsort12 add column it int not null;
Query OK, 0 righe influenzate (6.27 sec)
Records: 0 Duplicates: 0 Warnings: 0

Faccio un breve analisi:

2017-08-03T19:46:54.781453Z 3 [Note] (acquire_lock)L'acquisizione di questo MDL LOCK è andata a buon fine!
2017-08-03T19:46:54.781487Z 3 [Note] (>MDL PRINT) L'ID del thread è 3: 
2017-08-03T19:46:54.781948Z 3 [Note] (->MDL PRINT) Il nome del database è: test 
2017-08-03T19:46:54.781990Z 3 [Note] (-->MDL PRINT) Il nome dell'oggetto è: testsort12 
2017-08-03T19:46:54.782026Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è: TABLE 
2017-08-03T19:46:54.782060Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.782096Z 3 [Note] (------>MDL PRINT) Mdl duration is: MDL_TRANSACTION 
2017-08-03T19:46:54.782175Z 3 [Note] (------->MDL PRINT) Mdl status is: EMPTY 
2017-08-03T19:46:54.803898Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK will upgrade
2017-08-03T19:46:54.804201Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T19:46:54.804240Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T19:46:54.804254Z 3 [Note] (->MDL PRINT) Nome del database è:test 
2017-08-03T19:46:54.804267Z 3 [Note] (-->MDL PRINT) Nome dell'oggetto è:testsort12 
2017-08-03T19:46:54.804280Z 3 [Note] (--->MDL PRINT) Nome dello spazio dei nomi è:TABLE 
2017-08-03T19:46:54.804293Z 3 [Note] (----->MDL PRINT) Mdl type : MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.804306Z 3 [Note] (------>MDL PRINT) Durata del Mdl è:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Note] (------->MDL PRINT) Stato del Mdl è:EMPTY 
2017-08-03T19:46:54.855563Z 3 [Note] (downgrade_lock)THIS MDL LOCK will downgrade
2017-08-03T19:46:54.855693Z 3 [Note] (downgrade_lock) to this MDL lock
2017-08-03T19:46:54.855706Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T19:46:54.855717Z 3 [Note] (->MDL PRINT) DB_name is: test 
2017-08-03T19:46:54.856053Z 3 [Note] (-->MDL PRINT) OBJ_name is: testsort12 
2017-08-03T19:46:54.856069Z 3 [Note] (--->MDL PRINT) Namespace is: TABLE 
2017-08-03T19:46:54.856082Z 3 [Note] (----->MDL PRINT) Mdl type is: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.856094Z 3 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T19:46:54.856214Z 3 [Note] (------->MDL PRINT) Mdl status is:EMPTY 
2017-08-03T19:47:00.260166Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK will upgrade
2017-08-03T19:47:00.304057Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T19:47:00.304090Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T19:47:00.304105Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T19:47:00.304119Z 3 [Note] (-->MDL PRINT) OBJ_name is:testsort12 
2017-08-03T19:47:00.304132Z 3 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T19:47:00.304181Z 3 [Note] (----->MDL PRINT) Mdl type is:MDL_EXCLUSIVE(X) 
2017-08-03T19:47:00.304196Z 3 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T19:47:00.304211Z 3 [Note] (------->MDL PRINT) Mdl status is:EMPTY 
2017-08-03T19:47:01.032329Z 3 [Note] (acquire_lock)THIS MDL LOCK acquire ok! 

Prima di tutto, ottenere la tabella testsort12

2017-08-03T19:46:54.781487 Ottenimento MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:46:54.804293 Aggiornamento MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.855563 Discesa MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:47:00.304057 Aggiornamento MDL_EXCLUSIVE(X) 

Perché comunque l'operazione alter è piuttosto lunga, dal tempo vediamo che dal 2017-08-03T19:46:54 all'2017-08-03T19:47:00
In realtà, è il più耗时ivo, qui è l'operazione di COPY reale, ma questo processo è effettivamente in modalità MDL SU quindi non blocca DML/SELECT operazioni.
Ecco un avviso: l'ONLINE DDL è solo non bloccare DML/SELECT durante la fase di COPY, quindi è meglio farlo quando la pressione del database è bassa
Ad esempio, se c'è un DML non confermato o un SELECT non completato, SW SR blocca necessariamente X, mentre X può bloccare tutto e ha la priorità più alta. Questo porta a
Il fenomeno è dovuto al fatto che DML non è stato confermato blocca l'operazione DDL e DDL blocca tutte le operazioni, praticamente blocca tutte le tabelle di questo TABLE. Per altri parte ALGORITHM=COPY quasi identico, ma durante la fase di COPY viene utilizzato il blocco SNW, quindi vediamo prima il blocco SNW

8、MDL_SHARED_NO_WRITE(SNW)

SU può essere aggiornato a SNW e SNW può essere aggiornato a X, come menzionato in precedenza per ALGORITHM=COPY, per proteggere l'integrità dei dati.
Guardiamo prima la sua compatibilità

   Request | Granted requests for lock          
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNW    | +  +  +  -  -  -  +  -  -  - |

Si può vedere che SR può ma SW non può, ovviamente anche bloccare DML (SW) ma SELECT (SR) non blocca, di seguito fornisco solo la parte chiave

mysql> alter table testsort12 add column ik int not null, ALGORITHM=COPY ;
2017-08-03T20:07:58.413215Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T20:07:58.413241Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T20:07:58.413257Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T20:07:58.413273Z 3 [Note] (-->MDL PRINT) OBJ_name is:testsort12 
2017-08-03T20:07:58.413292Z 3 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T20:07:58.413308Z 3 [Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:07:58.413325Z 3 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T20:07:58.413341Z 3 [Note] (------->MDL PRINT) Mdl status is:EMPTY 
2017-08-03T20:08:25.392006Z 3 [Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T20:08:25.392024Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T20:08:25.392086Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T20:08:25.392159Z 3 [Note] (-->MDL PRINT) OBJ_name is:testsort12 
2017-08-03T20:08:25.392199Z 3 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T20:08:25.392214Z 3 [Note] (----->MDL PRINT) Mdl type is:MDL_EXCLUSIVE(X) 
2017-08-03T20:08:25.392228Z 3 [Note] (------>MDL PRINT) La durata di Mdl è:MDL_TRANSACTION 
2017-08-03T20:08:25.392242Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è:EMPTY 
2017-08-03T20:07:58.413308 ha ottenuto MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:08:25.392006 è stato aggiornato a MDL_EXCLUSIVE(X) 

Questo è il tempo effettivo di COPY dal 2017-08-03T20:07:58.413308 al 2017-08-03T20:08:25.392006, è chiaro che durante tutto il periodo di COPY è possibile solo DML
E non è possibile SELECT, è anche una differenza chiave tra ALGORITHM=COPY e ALGORITHM=INPLACE.

9、MDL_SHARED_READ_ONLY(SRO)

Utilizzato per la语句 LOCK TABLES READ

La compatibilità è la seguente

    Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SRO    | +  +  +  -  -  +  +  +  -  - |
Il DML è bloccato (SW) ma SELECT (SR) è ancora possibile.
mysql> lock table testsort12 read;
Query OK, 0 rows affected (0.01 sec)
2017-08-03T21:08:27.267947Z 3 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T21:08:27.267979Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T21:08:27.268009Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T21:08:27.268040Z 3 [Note] (-->MDL PRINT) OBJ_name is:testsort12 
2017-08-03T21:08:27.268070Z 3 [Note] (--->MDL PRINT) Namespace is:TABLE 
2017-08-03T21:08:27.268113Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_SHARED_READ_ONLY(SRO) 
2017-08-03T21:08:27.268145Z 3 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_TRANSACTION 
2017-08-03T21:08:27.268175Z 3 [Note] (------->MDL PRINT) Lo stato di Mdl è: EMPTY 

10、MDL_SHARED_NO_READ_WRITE(SNRW)

Usato per la frase lock table write

Compatibilità:

    Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNRW   | +  +  -  -  -  -  -  -  -  - |

Si può vedere che DML(SW) e SELECT(SR) sono bloccati, solo SH può funzionare, e può anche DESC(SH).

mysql> lock table testsort12 write;
Query OK, 0 righe influenzate (0.00 sec)
2017-08-03T21:13:07.113347Z 3 [Note] (acquire_lock) L'acquisizione di questo MDL LOCK è andata a buon fine!
2017-08-03T21:13:07.113407Z 3 [Note] (>MDL PRINT) L'ID del thread è 3: 
2017-08-03T21:13:07.113435Z 3 [Note] (--->MDL PRINT) Lo spazio dei nomi è: GLOBAL 
2017-08-03T21:13:07.113458Z 3 [Note] (---->MDL PRINT) Il percorso rapido è: (Y)
2017-08-03T21:13:07.113482Z 3 [Note] (----->MDL PRINT) Il tipo di Mdl è: MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113505Z 3 [Note] (------>MDL PRINT) La durata di Mdl è: MDL_STATEMENT 
2017-08-03T21:13:07.113604Z 3 [Note] (------->MDL PRINT) Mdl status is:EMPTY 
2017-08-03T21:13:07.113637Z 3 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T21:13:07.113660Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T21:13:07.113681Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T21:13:07.113703Z 3 [Note] (-->MDL PRINT) OBJ_name is: 
2017-08-03T21:13:07.113725Z 3 [Note] (--->MDL PRINT) Namespace is:SCHEMA 
2017-08-03T21:13:07.113746Z 3 [Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T21:13:07.113768Z 3 [Note] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113791Z 3 [Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION 
2017-08-03T21:13:07.113813Z 3 [Note] (------->MDL PRINT) Mdl status is:EMPTY 
2017-08-03T21:13:07.113842Z 3 [Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T21:13:07.113865Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T21:13:07.113887Z 3 [Note] (->MDL PRINT) DB_name is:test 
2017-08-03T21:13:07.113922Z 3 [Note] (-->MDL PRINT) Nome oggetto è:testsort12 
2017-08-03T21:13:07.113945Z 3 [Note] (--->MDL PRINT) Nome spazio è:TABLE 
2017-08-03T21:13:07.113975Z 3 [Note] (----->MDL PRINT) Tipo Mdl è:MDL_SHARED_NO_READ_WRITE(SNRW) 
2017-08-03T21:13:07.113998Z 3 [Note] (------>MDL PRINT) Durata Mdl è:MDL_TRANSACTION 
2017-08-03T21:13:07.114021Z 3 [Note] (------->MDL PRINT) Stato Mdl è:EMPTY 

Oltre a lock table, è necessario anche IX lock su GLOBAL e SCHEMA, in altre parole flush tables with read lock; blocca
lock table testsort12 write; ma lock table testsort12 read non blocca.

11、MDL_EXCLUSIVE(X)

Utilizzato per vari operazioni DDL, i commenti sono CREATE/DROP/RENAME TABLE operazioni, in realtà quasi tutti i DDL coinvolgono questo blocco, come analizzato sopra
operazione di aggiungere una colonna, ma la durata è generalmente breve.

Compatibilità:

   Request | Richieste concesse per il blocco         |
    type  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   X     | -  -  -  -  -  -  -  -  -  - |

Non c'è blocco imprevisto sopra, ma è bloccato da tutto

Per esempio, l'operazione di aggiungere una colonna appena eseguita

2017-08-03T19:46:54.804240Z 3 [Note] (>MDL PRINT) Thread id is 3: 
2017-08-03T19:46:54.804254Z 3 [Note] (->MDL PRINT) Nome del database è:test 
2017-08-03T19:46:54.804267Z 3 [Note] (-->MDL PRINT) Nome dell'oggetto è:testsort12 
2017-08-03T19:46:54.804280Z 3 [Note] (--->MDL PRINT) Nome dello spazio dei nomi è:TABLE 
2017-08-03T19:46:54.804293Z 3 [Note] (----->MDL PRINT) Tipo del Mdl è:MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.804306Z 3 [Note] (------>MDL PRINT) Durata del Mdl è:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Note] (------->MDL PRINT) Stato del Mdl è:EMPTY 

Sezione sorgente dei commenti

enum enum_mdl_type {
 /*
  Blocco metadati esclusivo di intenzione. Utilizzato solo per blocchi a livello di contesto.
  Il proprietario di questo tipo di blocco può acquisire blocchi esclusivi upgradeabili
  oggetti individuali.
  Compatibile con altri blocchi IX, ma incompatibile con S e
  Blocco X.
 */
 MDL_INTENTION_EXCLUSIVE= 0,
 /*
  Blocco metadati condiviso.
  Da utilizzare nei casi in cui siamo interessati solo alla metadati dell'oggetto
  nessuna intenzione di accedere ai dati dell'oggetto (ad esempio per memorizzare
  routine o durante la preparazione delle istruzioni preparate).
  Utilizziamo anche male questo tipo di blocco per aprire HANDLER, poiché il blocco
  acquisito da questa dichiarazione deve essere compatibile con il blocco acquisito
  attraverso la dichiarazione LOCK TABLES ... WRITE, ossia SNRW (Non possiamo farcela semplicemente
  di acquisire un blocco S al tempo HANDLER ... OPEN e di aggiornarlo a SR
  un blocco per HANDLER ... READ poiché non risolve il problema con la necessità
  per abortire le istruzioni DML che aspettano un blocco a livello di tabella mentre hanno
  aprire HANDLER nella stessa connessione).
  Per evitare che si verifichi un blocco morto che potrebbe verificarsi quando il blocco SNRW viene aggiornato a
  il blocco X per la tabella su cui c'è un blocco S attivo che è posseduto da
  il thread che aspetta a sua volta il blocco a livello di tabella posseduto dal thread
  durante l'aggiornamento dobbiamo utilizzare thr_abort_locks_for_thread()
  facilità in tale situazione.
  Questo problema non si verifica per i blocchi sulle routine memorizzate poiché non esiste
  usare i blocchi SNRW per loro. Non si verifica nemmeno quando vengono utilizzati i blocchi S
  durante le chiamate PREPARE poiché non vengono acquisiti blocchi a livello di tabella in questo
  caso.
 */
 MDL_SHARED,
 /*
  Un blocco di metadati condiviso a alta priorità.
  Utilizzato per casi in cui non c'è l'intenzione di accedere ai dati dell'oggetto (cioè
  dati nella tabella).
  "Priorità alta" significa che, a differenza degli altri lock condivisi, è concesso
  ignorando le richieste in sospeso per i lock esclusivi. Destinato all'uso in
  casi in cui abbiamo bisogno solo di accedere ai metadati e non ai dati, ad esempio quando
  riempie una tabella INFORMATION_SCHEMA.
  Poiché il lock SH è compatibile con il lock SNRW, la connessione che
  che mantiene il lock SH non dovrebbe cercare di acquisire alcun tipo di lock a livello di tabella
  o lock a livello di riga, poiché questo può portare a un blocco. Inoltre, dopo
  acquisizione di SH lock, la connessione non dovrebbe aspettare altre
  risorsa, poiché potrebbe causare la fame per i lock X e un potenziale
  blocco durante l'aggiornamento di SNW o SNRW a X lock (ad esempio, se il)
  l'aggiornamento della connessione mantiene la risorsa che viene attesa).
 */
 MDL_SHARED_HIGH_PRIO,
 /*
  Un blocco di metadati condiviso per casi in cui c'è l'intenzione di leggere dati
  dalla tabella.
  Una connessione che mantiene questo tipo di lock può leggere i metadati della tabella e leggere
  i dati della tabella (dopo aver acquisito i blocchi di tabella e livello di riga appropriati).
  Questo significa che uno può acquisire solo TL_READ, TL_READ_NO_INSERT e
  simili blocchi di livello di tabella sulla tabella se uno mantiene un blocco SR MDL su di essa.
  Da utilizzare per tabelle in SELECT, sottoselettive e LOCK TABLE ... READ
  istruzioni.
 */
 MDL_SHARED_READ,
 /*
  Un blocco di metadata condiviso per casi in cui c'è l'intenzione di modificare
  (e non solo leggere) i dati nella tabella.
  Una connessione che mantiene un blocco SW può leggere i metadati della tabella e modificare o leggere
  i dati della tabella (dopo aver acquisito i blocchi di tabella e livello di riga appropriati).
  Da utilizzare per tabelle da modificare con INSERT, UPDATE, DELETE
  istruzioni, ma non LOCK TABLE ... WRITE o DDL). Anche prese da
  SELECT ... FOR UPDATE.
 */
 MDL_SHARED_WRITE,
 /*
  Una versione del blocco MDL_SHARED_WRITE con priorità inferiore a
  bloccature MDL_SHARED_READ_ONLY. Utilizzate dalle istruzioni DML che modificano
  tabelle e utilizzando la clausola LOW_PRIORITY.
 */
 MDL_SHARED_WRITE_LOW_PRIO,
 /*
  Un blocco di metadata condiviso aggiornabile che consente aggiornamenti contemporanei e
  le letture dei dati della tabella.
  Una connessione che mantiene questo tipo di lock può leggere i metadati della tabella e leggere
  dati della tabella. Non dovrebbe modificare i dati poiché questo lock è compatibile con
  lock SRO.
  Può essere aggiornato a SNW, SNRW e lock X. Una volta che il lock SU è aggiornato a X
  o può accadere liberamente la modifica dei dati SNRW lock.
  Da utilizzare per la prima fase di ALTER TABLE.
 */
 MDL_SHARED_UPGRADABLE,
 /*
  Un lock di metadati condiviso per i casi in cui dobbiamo leggere dati dalla tabella
  e bloccare tutte le modifiche concorrenti a essa (sia per i dati che per i metadati).
  Usato dalla dichiarazione LOCK TABLES READ.
 */
 MDL_SHARED_READ_ONLY,
 /*
  Un lock di metadati condiviso aggiornabile che blocca tutti gli tentativi di aggiornamento
  dati della tabella, permettendo le letture.
  Una connessione che mantiene questo tipo di lock può leggere i metadati della tabella e leggere
  dati della tabella.
  Può essere aggiornato a un blocco di metadati X.
  Nota che questo tipo di lock non è compatibile con SNRW o SW
  tipi di lock, acquisendo i lock a livello di motore appropriati per la lettura
  (TL_READ* per MyISAM, lock di riga condivisi in InnoDB) dovrebbe essere
  senza conflitti.
  Da utilizzare per la prima fase di ALTER TABLE, quando si copia dati tra
  tabella, per permettere SELECTs concorrenti dalla tabella, ma non UPDATEs.
 */
 MDL_SHARED_NO_WRITE,
 /*
  Un blocco di metadati condiviso aggiornabile che permette ad altre connessioni
  di accedere ai metadati della tabella, ma non ai dati.
  Blocca tutte le tentativi di leggere o aggiornare i dati della tabella, mentre permette
  query INFORMATION_SCHEMA e SHOW.
  Una connessione che mantiene questo tipo di blocco può leggere i metadati della tabella, modificarli e
  leggere i dati della tabella.
  Può essere aggiornato a un blocco di metadati X.
  Da utilizzare per l'istruzione LOCK TABLES WRITE.
  Non compatibile con alcun altro tipo di blocco tranne S e SH.
 */
 MDL_SHARED_NO_READ_WRITE,
 /*
  Un blocco di metadati esclusivo.
  Una connessione che mantiene questo blocco può modificare sia i metadati che i dati della tabella.
  Non può essere concesso alcun altro tipo di blocco di metadati mentre questo blocco è mantenuto.
  Da utilizzare per le istruzioni CREATE/DROP/RENAME TABLE e per l'esecuzione di
  alcuni fasi di altre istruzioni DDL.
 */
 MDL_EXCLUSIVE,
 /* Questo dovrebbe essere l'ultimo !!! */
 MDL_TYPE_END};
/** Durata del blocco di metadati. */
enum enum_mdl_duration {}}
 /**
  I lock con durata dello statement vengono rilasciati automaticamente alla fine
  dello statement o della transazione.
 */
 MDL_STATEMENT= 0,
 /**
  I lock con durata della transazione vengono rilasciati automaticamente alla fine
  della transazione.
 */
 MDL_TRANSACTION,
 /**
  I lock con durata esplicita sopravvivono alla fine dello statement e della transazione.
  Devono essere rilasciati esplicitamente chiamando MDL_context::release_lock().
 */
 MDL_EXPLICIT,
 /* Questo dovrebbe essere l'ultimo ! */
 MDL_DURATION_END };
/**
  Namespace degli oggetti.
  Sic: quando si aggiunge un nuovo membro a questo enum, assicurarsi di
  aggiorna l'array m_namespace_to_wait_state_name in mdl.
  Esistono diversi tipi di oggetti in diversi namespace
   - GLOBAL è utilizzato per il blocco di lettura globale.
   - TABLESPACE è per gli spazi di archiviazione.
   - SCHEMA è per gli schemi (noto anche come database).
   - TABLE è per le tabelle e le viste.
   - FUNCTION è per le funzioni memorizzate.
   - PROCEDURE è per le procedure memorizzate.
   - TRIGGER è per i trigger.
   - EVENT è per gli eventi del pianificatore degli eventi.
   - COMMIT serve a attivare il blocco di lettura globale per i commit.
   - USER_LEVEL_LOCK è per i lock a livello utente.
   - LOCKING_SERVICE è per il servizio di lock RW del plugin di nome
  Notare che non esiste locking di metadati sui trigger,
  è necessario avere uno spazio nome separato per loro poiché
  MDL_key viene anche utilizzato al di fuori del sottosistema MDL.
  Anche notare che le richieste in attesa di lock a livello utente ricevono trattamenti speciali
  La gestione in attesa viene annullata se la connessione con il client viene persa.
 */
 enum enum_mdl_namespace { GLOBAL=0,
              TABLESPACE,
              SCHEMA,
              TABLE,
              FUNCTION,
              PROCEDURE,
              TRIGGER,
              EVENT,
              COMMIT,
              USER_LEVEL_LOCK,
              LOCKING_SERVICE,
              BACKUP,
              BINLOG,
              /* Questo dovrebbe essere l'ultimo ! */
              NAMESPACE_END };
Ti potrebbe interessare