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