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

Analyse des MDL-Locks (MDL Lock) - Problems bei MYSQL METADATA LOCK

1. Einleitung

MDL-Sperren in MYSQL sind immer ein Problem, das viele Menschen beschäftigt. Wenn wir über Sperren sprechen, neigen wir dazu, die Gap Lock, Next Key Lock und Row Lock auf der unteren Ebene von INNODB zu bevorzugen, da sie gut verständlich und leicht zu beobachten sind. Für MDL LOCK jedoch wissen wir sehr wenig, da es schwer zu beobachten ist und man nur durch Anzeigen von 'show processlist' auf Probleme stoßen kann

Der einfache Status 'Wartend auf Tabellenmetadaten-Sperre' ist in Wirklichkeit ein sehr komplexer Subsystem der oberen Ebene von MYSQL, das über ein eigenes Deadlock-Detektionsmechanismus verfügt

(ungerichteter Graph?Daher ist es, was die meisten von uns als 'Tabelle sperren' bezeichnen, und seine Bedeutung und Schwere ist offensichtlich. Der Autor hat einige (Eisbergspitze) gelernt, um seinen Bedarf zu erfüllen, ohne jedoch in der Lage zu sein, den gesamten Code zu lesen. Der Autor hat jedoch durch Hinzufügen einer Druckfunktion für TICKET den MDL LOCK-Sperrvorgang vollständig ausgedruckt, um das Lernen und die Forschung zu erleichtern. Nachfolgend wird von einigen Grundlagen ausgegangen und gezeigt, welche Änderungen vorgenommen wurden, und schließlich wird jeder MDL TYPE getestet und analysiert. Wenn man die grundlegenden Konzepte und die hinzugefügte Druckfunktion nicht interessiert, kann man direkt auf den fünften Teil 'Sperrentest' verweisen, aber ohne Grundlagenkenntnisse könnte es etwas schwierig sein, es zu verstehen.

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

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

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

调用栈帧

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

----Deadlock检测出错码:

{"ER_LOCK_DEADLOCK", 1213, "Wird ein Deadlock beim Versuch, einen Lock zu erlangen, gefunden; versuchen Sie, die Transaktion neu zu starten" }
ERROR 1213 (40001): Wird ein Deadlock beim Versuch, einen Lock zu erlangen, gefunden; versuchen Sie, die Transaktion neu zu starten

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 wird für den globalen Lese-Schutz verwendet.

- TABLESPACE ist für Tablespaces.

- SCHEMA ist für Schemata (alias Datenbanken).

- TABLE ist für Tabellen und Ansichten.

- FUNCTION ist für gespeicherte Funktionen.

- PROCEDURE ist für gespeicherte Verfahren.

- TRIGGER ist für Trigger.

- EVENT ist für Ereignis-Scheduler-Ereignisse.

- COMMIT ist für die Aktivierung des globalen Lese-Locks, um Commits zu blockieren.

- USER_LEVEL_LOCK ist für Benutzer-Ebene Locks.

- LOCKING_SERVICE ist für das Namensplugin RW-Lock-Dienst

3、实现分类

范围锁定:通常对应全局MDL LOCK,如带有读取锁的flush table,命名空间空间:GLOBAL 类型:S

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

以下是源码中的注释:

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

4、MDL兼容矩阵

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

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

Dies erfordert nicht viele Erklärungen, man kann die Kommentare im Quellcode betrachten

MDL_STATEMENT: Locks mit Anweisungs Dauer werden automatisch freigegeben am Ende
       des Anweisungs- oder Transaktionsablaufs.
MDL_TRANSACTION: Locks mit Transaktionsdauer werden automatisch freigegeben am Ende
        des Transaktionsablaufs
MDL_EXPLICIT: Locks mit expliziter Dauer überleben das Ende des Anweisungs- und Transaktionsablaufs.
       Sie müssen explizit durch Aufruf von MDL_context::release_lock() freigegeben werden.

6、MDL LOCK FAST PATH (unobtrusive) oder SLOW PATH (obtrusive)

Zweck der Verwendung von zwei verschiedenen Methoden ist die Optimierung der Implementierung von MDL_lock, im Folgenden sind die Kommentare im Quellcode

A) "unobtrusive" Lock-Typen
      1) Jeder Typ aus dieser Menge sollte mit allen anderen
        ) Typen aus der Menge (einschließlich selbst).
      2) Diese Typen sollten für DML-Operationen häufig vorkommen
     Unser Ziel ist es, die Akquisition und Freigabe von Locks dieses
     durch Vermeidung komplexer Überprüfungen und Manipulationen an m_waiting/
     m_granted 位图/Listen. Wir ersetzen sie durch eine Überprüfung von und
     Erhöhung/Verringerung von Integer-Zählern.
     Wir nennen diesen Typ der Akquisition/den "schnellen Weg" freigeben.
     Die Verwendung des "schnellen Wegs" verringert die Größe des kritischen Abschnitts, der mit
     mit MDL_lock::m_rwlock lock im allgemeinen Fall und damit erhöht
     可伸缩性。
     获取量增加/特定类型的释放
     "unobtrusive" 锁增加/减少在
     MDL_lock::m_fast_path_state 由这个函数返回。
B) "obtrusive" 锁类型
      1) 同类型的已授权或挂起的锁与
        一些其他类型的锁或与自身进行操作。
      2) 对于DML操作来说不常见
     这些锁必须始终通过在
     m_waiting/m_granted 位图/列表的情况下,即我们必须使用 "slow path"
     对于它们。此外,在存在活动/挂起的锁
     "obtrusive" 锁集,我们必须使用 "slow path" 来获取,即使是
     "unobtrusive" 类型。

7、MDL_request类

也就是通过语句解析后需要获得的MDL LOCK的需求,然后通过这个类对象在MDL子系统
进行MDL LOCK申请,大概包含如下一些属性

/** 元数据锁的类型。 */
 enum enum_mdl_type type; //需求的类型
 /** 所需锁的持续时间。 */
 enum enum_mdl_duration duration; //持续时间
 /**
  Zeiger für die Teilnahme an der Liste der Sperranfragen für diesen Kontext.
 */
 MDL_request *next_in_list; //双向链表实现
 MDL_request **prev_in_list;
 /**
  对该锁请求的锁票对象的指针。
  Gültig nur, wenn diese Sperranfrage erfüllt wird.
 */
 MDL_ticket *ticket; //Beachten Sie, dass dies erfolgreich angefordert wird (wenn nicht gewartet wird), auf ein tatsächliches TICKET verweist, andernfalls ist es NULL
 /** Eine Sperre wird auf Basis eines voll qualifizierten Namens und Typs angefordert. */
 MDL_key key;//Beachten Sie, dass dies hier ein MDL_KEY-Typ ist, der hauptsächlich der zuvor erwähnte NAMESPACE ist+DB+OBJECT_NAME

MDL_key-Klasse, das ist der tatsächliche NAMESPACE+DB+OBJECT_NAME, den gesamten in ein char-Array legen, das in MDL_LOCK und MDL_REQUEST vorkommt

privat:

uint16 m_length;

uint16 m_db_name_length;

char m_ptr[MAX_MDLKEY_LENGTH];//hierher gestellt

8、MDL_ticket

Wie ein Ticket, wenn MDL LOCK erhalten wird, gibt MDL_request sicherlich ein Ticket zurück, wenn darauf gewartet wird, wird nicht MDL_context::acquire_lock im Quellcode aufgerufen

Dies kann beobachtet werden. Natürlich ist dies auch eine der Klassen, die ich hauptsächlich beobachte

/**
  Zeiger für die Teilnahme an der Liste der Sperranfragen für diesen Kontext.
  Kontext privat. Wie erläutert, ist dies die Formation der Liste der Liste im Kontext, die threadeigener ist
 */
 MDL_ticket *next_in_context;
 MDL_ticket **prev_in_context;
 /**
  Zeiger für die Teilnahme an der Liste der erfüllten/ausstehende Anfragen
  für die Sperre. Extern zugänglich. Wie erläutert, ist dies die Formation der Liste der MDL_LOCK, die global ist
 */
 MDL_ticket *next_in_lock;
 MDL_ticket **prev_in_lock;
/**
  Kontext des Besitzers des MDL-Sperreningstickets. Extern zugänglich.
  Es ist offensichtlich, dass hier auf den Besitzer dieses Tickets verwiesen wird, nämlich MDL_context, der ein Attribut der Thread ist
 */
 MDL_context *m_ctx; 
 /**
  Pointer to the lock object for this lock ticket. Externally accessible.
  It is obvious that this is a pointer to MDL_LOCK
 */
 MDL_lock *m_lock;
 /**
  Indicates that the ticket corresponds to a lock acquired using "fast path"
  algorithm. Particularly this means that it was not included into
  MDL_lock::m_granted bitmap/list and instead is accounted for by
  MDL_lock::m_fast_path_locks_granted_counter
  Here it represents whether it is a FAST PATH. From the comments, it can be seen that the fast path method will not be included in the MDL LOCK
  Instead of occupying the granted bitmap and list, a counter m_fast_path_locks_granted_counter is used
  In this way, the cost is definitely 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 very detailed to directly refer to the source code comments, and here are the several properties 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;

10MDL_context

Dies ist eine so genannte Kontextstruktur, die das Ganze MYSQL-Thread- und MDL-Lock-Subsystem interagiert, die viele Methoden und Eigenschaften enthält, die ich am meisten interessieren:

/**
  Wenn unser Anforderung für einen Lock geplant ist oder durch Deadlock abgebrochen wird
  Detector, das Ergebnis wird in dieser Klasse protokolliert.
 */
 MDL_wart m_wait;
/**
  Liste aller von dieser Verbindung erlangten MDL-Tickets.
  Dies ist ein Array von Listen mit verschiedenen MDL-Lock-Dauern. Es ist
  MDL_STATEMENT eine Liste
  MDL_TRANSACTION eine Liste
  MDL_EXPLICIT eine Liste
 */
Ticket_list m_tickets[MDL_DURATION_END];
//Dies ist ein Zeiger auf eine Unterklasse, der ein Objekt der Unterklasse zeigt, ein typisches Beispiel für die Überschreibung von virtuellen Funktionen, der tatsächlich auf einen Thread zeigt
/*
class THD :public MDL_context_owner,
      public Query_arena,
      public Open_tables_state
*/
MDL_context_owner *m_owner;

11MDL_wart

Diese Klasse ist hauptsächlich für den aktuellen Ticket-Status verantwortlich

enum_wait_status m_wait_status;

enthält

LEER Initialisierung

ERHALTEN Erfolgreich erlangt

OPFER Deadlock

ZEITÜBERSCHREITUNG Zeitüberschreitung

BEENDETBENENDETB

12Wartezustand

PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
{
 {0, "Wartend auf globale Lese-Sperre", 0},
 {0, "Wartend auf Tablespace-Metadaten-Sperre", 0},
 {0, "Wartend auf Schema-Metadaten-Sperre", 0},
 {0, "Wartend auf Tabellen-Metadaten-Sperre", 0},
 {0, "Wartend auf stored function metadata lock", 0}
 {0, "Wartend auf stored procedure metadata lock", 0},
 {0, "Wartend auf trigger metadata lock", 0},
 {0, "Wartend auf event metadata lock", 0},
 {0, "Wartend auf commit lock", 0},
 {0, "User lock", 0}, /* Kompatibel mit alten Status. */
 {0, "Wartend auf locking service lock", 0},
 {0, "Wartend auf backup lock", 0},
 {0, "Wartend auf binlog lock", 0}
};

Drittes Kapitel: Hinzufügen der MDL LOCK Druckfunktion

die beste Methode zur Untersuchung von MDL LOCK-Sperren ist natürlich, den Ablauf der MDL-Sperren, Aufgrades und Downgrades zu erhalten, da der Quellcode sehr umfangreich ist und nicht umfassend behandelt werden kann
Obwohl5.7hinzugefügt

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 * aus performance_schema.metadata_locks

in dieser Weise MDL LOCK zu betrachten, aber wenn man wirklich sehen will, welche MDL LOCK eine Anweisung tatsächlich erhalten hat, zeigt sich, dass dies recht begrenzt ist, daher wurde der Autor in mdl.cc eine Funktion hinzugefügt mit folgendem Prototyp

/*p_ticket als Parameter*/

int my_print_ticket(const MDL_ticket* p_ticket)

und hat in der mdl_ticket-Klasse diese Funktionsprototyp hinzugefügt, da als Freundefunktion, da private Member sonst nicht erreicht werden können, und die öffentlichen Methoden sind recht komplex

friend int my_print_ticket(const MDL_ticket* p_ticket);

Hauptinformationen über MDL LOCK werden wie folgt in das mysql err Log gedruckt:

Threading-ID durch p_ticket->m_ctx->get_thd(); abrufen

mdl lock database name durch p_ticket->m_lock->key.db_name() abrufen

mdl lock object name durch p_ticket->m_lock->key.name() abrufen

mdl lock namespace durch p_ticket->m_lock->key.mdl_namespace() abrufen

mdl lock fast path durch p_ticket->m_is_fast_path abrufen, wird ausgegeben, wenn wahr,否则不输出

mdl lock type durch p_ticket->m_type abrufen

mdl lock duration durch p_ticket->m_duration abrufen

Die folgenden Informationen werden ausgegeben:

2017-08-03T07:34:21.720583Z 3 [Notiz] (>MDL PRINT) Thread id ist 3:

2017-08-03T07:34:21.720601Z 3 [Notiz] (->MDL PRINT) DB_name ist:test

2017-08-03T07:34:21.720619Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist: test

2017-08-03T07:34:21.720637Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE

2017-08-03T07:34:21.720655Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)

2017-08-03T07:34:21.720673Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE(SW)

2017-08-03T07:34:21.720692Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION

Das ist ähnlich wie die Informationen in metadata_locks, dies ist hier mein Thread id, der aus show processlist kommt, aber ich kann die historische Informationen der Sperre erhalten. Hier habe ich auch keine SPERRSTATUS: ZUGESTEILT, aber ich kann das aus der Logik von MDL_context::acquire_lock ablesen

mysql> select * von performance_schema.metadata_locks\G
*************************** 1Zeile ***************************
OBjektTYP: TABELLE
OBjektSCHEMA: test
OBjektNAME: test
OBjektINSTANZBEGINN: 140734412907760
SPERRTYP: GEGENLÄUFIGES EINLESSEN
SPERREDAUER: TRANSAKTION
SPERRSTATUS: ZUGESTEILT
QUELLE: sql_parse.cc:6314
OWNER_THREAD_ID: 39
OWNER_EVENT_ID: 241

Vier, Druckfunktionen an geeigneten Positionen hinzufügen, um zu beobachten

Da wir die Sperre, Aufwertung und Abwertung von MDL LOCK untersuchen möchten, müssen wir ihre Funktions-Übergänge finden und dann an geeigneten Positionen Druckfunktionen hinzufügen, um zu beobachten. Unten sind die Druckpositionen angegeben, die meisten der Quelldaten sind gelöscht, bitte schauen Sie sich die Quelldaten selbst an.

1、Sperren: MDL_context::acquire_lock

bool
MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
{
 if (mdl_request->ticket) //Erfolgreich ticket erhalten
 {
  /*
   Wir haben es geschafft, den Lock ohne Warten zu erwerben.
   MDL_lock, MDL_context und MDL_request wurden aktualisiert
   entsprechend können wir einfach Erfolg zurückgeben.
  */
  //REQUESET-Ticket-Erwerb erfolgreich, hier wird gedruckt
  return FALSE;
 {}
 /*
  Unser Versuch, den Lock ohne Warten zu erwerben, ist gescheitert.
  Infolgedessen haben wir einen MDL_ticket mit m_lock erhalten
  Mitglied, das auf den entsprechenden MDL_lock-Objekt hinweist, das
  hat MDL_lock::m_rwlock Schreib-locked.
 */
 //Der Versuch, den Lock ohne Warten zu erwerben, war nicht erfolgreich, daher wird er der MDL_lock-Warteschlange hinzugefügt
 lock= ticket->m_lock;
 lock->m_waiting.add_ticket(ticket);
 will_wait_for(ticket); //Deadlock-Detektion
 /* Es gibt einen gemeinsamen oder exklusiven Lock auf das Objekt. */
 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
 find_deadlock(); 
 //Hier wird der TICKET in den Warteprozess gedruckt
 if (lock->needs_notification(ticket) || lock->needs_connection_check())
 {
  {}
 done_waiting_for();//Nach dem Abschluss des Wartens wird das Warteschlangenmodell für die Deadlock-Detektion angepasst, um die aktuelle Warteedge (ungerichtetes Graph) zu entfernen
 //Natürlich haben wir hier ebenfalls durch Warten den Erfolg erreicht und den Status GRANTED erhalten
 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)
{
 /* Only allow downgrade from EXCLUSIVE and SHARED_NO_WRITE. */
 DBUG_ASSERT(m_type == MDL_EXCLUSIVE ||
       m_type == MDL_SHARED_NO_WRITE);
//此处打印出降级前的TICKET
 if (m_hton_notified)
 {
  mysql_mdl_set_status(m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
  m_ctx,->get_owner(),->notify_hton_post_release_exclusive(&m_lock->key);
  m_hton_notified= false;
  mysql_mdl_set_status(m_psi, MDL_ticket::GRANTED);
 {}
//函数结尾答应出降级后的TICKET
{}

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

bool
MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,
                 enum_mdl_type new_type,
                 ulong lock_wait_timeout)
{
 MDL_REQUEST_INIT_BY_KEY(&mdl_new_lock_request,
             &mdl_ticket->m_lock->key, new_type,
             MDL_TRANSACTION);//构造一个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;
 //下面进行一系列对MDL_LOCK的维护并且对所谓的合并操作
 /* 以下代码假设我们正在升级到“侵入式”类型的锁。 */
 DBUG_ASSERT(lock->is_obtrusive_lock(new_type));
 /* 合并获取的和原始的锁。@todo: 移动到方法中。 */
 mysql_prlock_wrlock(&lock->m_rwlock);
 if (is_new_ticket)
 {
  m_tickets[MDL_TRANSACTION].remove(mdl_new_lock_request.ticket);
  MDL_ticket::destroy(mdl_new_lock_request.ticket);
 {}
 //此处打印出来的升级后TICKET类型 
 DBUG_RETURN(FALSE);
{}

当然我现在只是在这些地方进行了打印,以后如果需要在其他地方答应加上函数就可以了。

五、各种MDL LOCK TYPE加锁测试

1、MDL_INTENTION_EXCLUSIVE(IX)

这个锁会在很多操作的时候都会出现,比如做任何一个DML/DDL操作都会触发,实际上DELETE/UPDATE/INSERT/FOR UPDATE等DML操作会在GLOBAL上加上IX锁,然后才会在本对象上加锁,而DDL语句至少会在GLOBAL上加上IX锁,对象所属SCHEMA上加上IX锁,本对象加锁。以下是DELETE触发的GLOABL IX MDL LOCK

2017-08-03T18:22:38.092100Z 3 [Hinweis] Test2:open_tables_for_query()
2017-08-03T18:22:38.092205Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T18:22:38.092242Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T18:22:38.092276Z 3 [Notiz] (--->MDL PRINT) Namespace ist:GLOBAL 
2017-08-03T18:22:38.092310Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T18:22:38.092344Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:22:38.092380Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_STATEMENT 
2017-08-03T18:22:38.092551Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Nachstehend sind die durch ALETER-Anweisungen ausgelösten GLOABL IX MDL LOCK und MDL LOCK auf Schema-Ebene

2017-08-03T18:46:05.894871Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T18:46:05.894915Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T18:46:05.894948Z 3 [Notiz] (--->MDL PRINT) Namespace ist:GLOBAL 
2017-08-03T18:46:05.894980Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T18:46:05.895012Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895044Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_STATEMENT 
2017-08-03T18:46:05.895076Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T18:46:05.895116Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T18:46:05.895147Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T18:46:05.895206Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T18:46:05.895243Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist: 
2017-08-03T18:46:05.895276Z 3 [Notiz] (--->MDL PRINT) Namespace ist:SCHEMA 
2017-08-03T18:46:05.895325Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T18:46:05.895357Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T18:46:05.895390Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T18:46:05.895421Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Daher ist dieser MDL LOCK überall präsent, und es gibt nur das Problem der Kompatibilität. Der typische IX-Lock ist in der Regel kompatibel, es sei denn, er trifft auf
S-Typ

2、MDL_SHARED(S)

Diese Sperre wird in der Regel in flush tables with read lock verwendet

mysql> flush tables with read lock;
Query OK, 0 Zeilen beeinflusst (0.01 sec)
2017-08-03T18:19:11.603911Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T18:19:11.603947Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T18:19:11.603971Z 3 [Notiz] (--->MDL PRINT) Namespace ist:GLOBAL 
2017-08-03T18:19:11.603994Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED(S) 
2017-08-03T18:19:11.604045Z 3 [Notiz] (------>MDL PRINT) Mdl duration is:MDL_EXPLICIT 
2017-08-03T18:19:11.604073Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T18:19:11.604133Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T18:19:11.604156Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T18:19:11.604194Z 3 [Notiz] (--->MDL PRINT) Namespace is:COMMIT 
2017-08-03T18:19:11.604217Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED(S) 
2017-08-03T18:19:11.604240Z 3 [Notiz] (------>MDL PRINT) Mdl duration is:MDL_EXPLICIT 
2017-08-03T18:19:11.604310Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Wir bemerken, dass sein Namespace GLOBAL und COMMIT sind, was darauf hindeutet, dass es sich um SCOPED LOCKs handelt, ihre TYPE ist S, daher ist es offensichtlich gemäß den Prinzipien der Kompatibilität
MDL IX und MDL S sind inkompatibel, flush tables with read lock; blockiert alle DELETE/UPDATE/INSERT/FOR UPDATE
und DML und DDL-Operationen (dieser Operationsarten benötigen normalerweise einen GLOBAL MDL IX-Lock)

3、MDL_SHARED_HIGH_PRIO(SH)

Dieser Lock wird ebenfalls oft verwendet, ohne es zu bemerken, zum Beispiel bei unseren allgemeinen desc-Operationen

Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SH    | +  +  +  +  +  +  +  +  +  - |
mysql> desc test.testsort10;
2017-08-03T19:06:05.843277Z 4 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T19:06:05.843324Z 4 [Notiz] (>MDL PRINT) Thread id ist 4: 
2017-08-03T19:06:05.843359Z 4 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:06:05.843392Z 4 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort10 
2017-08-03T19:06:05.843425Z 4 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:06:05.843456Z 4 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T19:06:05.843506Z 4 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_HIGH_PRIO(SH) 
2017-08-03T19:06:05.843538Z 4 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:06:05.843570Z 4 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Dieser Typ hat eine höhere Priorität, ist aber mit X inkompatibel. Es ist auch leicht zu verstehen, zum Beispiel kann in der Stage von rename keine desc-Operation durchgeführt werden.

4、MDL_SHARED_READ(SR)

Diese Sperre wird in der Regel in nicht aktuellen SELECTs verwendet, Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | 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 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T19:13:52.338813Z 4 [Notiz] (>MDL PRINT) Thread id ist 4: 
2017-08-03T19:13:52.338847Z 4 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:13:52.338883Z 4 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort10 
2017-08-03T19:13:52.338917Z 4 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:13:52.338950Z 4 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T19:13:52.339025Z 4 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_READ(SR) 
2017-08-03T19:13:52.339062Z 4 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:13:52.339097Z 4 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Hier muss noch einmal erwähnt werden, dass wir manchmal Situationen haben, in denen SELECT ebenfalls blockiert (z.B. in einem bestimmten Stadium von DDL, das ein object MDL X-Lock benötigt). Wir müssen uns beschweren
MySQL blockiert tatsächlich SELECT, was hier auch das Problem mit der Inkompatibilität zwischen object mdl lock X und SR ist (siehe die vorherige Kompatibilitätsmatrix).

5、MDL_SHARED_WRITE(SW)

dieser Lock wird in der Regel für DELTE/UPDATE/INSERT/FOR UPDATE und ähnlichen Operationen, die das Table sperren (aktuelle Lesung), umfassen DDL-Operationen nicht
Aber beachten Sie, dass DML-Operationen tatsächlich einen GLOBALen IX-Lock haben, der bereits erwähnt wurde, dieser Lock ist nur auf dem Objekt

Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | 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 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T19:25:41.218461Z 4 [Notiz] (>MDL PRINT) Thread id ist 4: 
2017-08-03T19:25:41.218493Z 4 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:25:41.218525Z 4 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort10 
2017-08-03T19:25:41.218557Z 4 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:25:41.218588Z 4 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T19:25:41.218620Z 4 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE(SW) 
2017-08-03T19:25:41.218677Z 4 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:25:41.218874Z 4 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

6、MDL_SHARED_WRITE_LOW_PRIO(SWL)

dieser Lock wird selten verwendet, Quellcodekommentare nur

Von DML-Anweisungen, die ändern

Tabellen und die LOW_PRIORITY-Klausel verwenden

wird verwendet

Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | 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 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T19:32:47.433521Z 4 [Notiz] (>MDL PRINT) Thread id ist 4: 
2017-08-03T19:32:47.433533Z 4 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:32:47.433547Z 4 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort10 
2017-08-03T19:32:47.433560Z 4 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:32:47.433572Z 4 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T19:32:47.433594Z 4 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE_LOW_PRIO(SWL) 
2017-08-03T19:32:47.433607Z 4 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:32:47.433620Z 4 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

7、MDL_SHARED_UPGRADABLE(SU)

Dieser Lock wird in der Regel in ALTER TABLE-Anweisungen verwendet, er kann auf SNW, SNRW, X aufgestuft werden, gleichzeitig kann zumindest der X-Lock auf SU herabgestuft werden

Tatsächlich ist er in INNODB ONLINE DDL sehr abhängig, DML(SW) und SELECT(SR) blockieren nicht

Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SU    | +  +  +  +  +  -  +  -  -  - |

Wir müssen seine Kompatibilität untersuchen. Zu sehen, in OBJECT LOCK sind (SELECT)SR (DML)SW erlaubt, während in SCOPED LOCK
Obwohl DML und DDL alle auf GLOBAL level gesperrt werden, sind ihre Typen alle IX, daher blockiert dieser SU-Lock nicht DML/SELECT-Leseschreiboperations treten in die INNODB-Engine-Ebene ein, die Grundlage für ONLINE DDL ist. Wenn die Inkompatibilität vorliegt, können Sie nicht in die INNODB-Engine-Ebene eintreten, geschweige denn ONLINE DDL), beachten Sie, dass ich hier von ALGORITHM=INPLACE und ohne LOCK spreche

(Für DDL-Operationen mit LOCK=DEFAULT oder ohne LOCK-Klausel) verwendet MySQL die niedrigste Ebene
von Sperren, die für diese Art von Operation verfügbar sind, gleichzeitig abgestimmte Abfragen, DML oder beide überall ermöglichen
möglich. Dies ist die Einstellung, die beim Erstellen von vor-geplant, vor-geprüften Änderungen, die Sie wissen, dass sie nicht
können keine Verfügbarkeitsprobleme aufgrund der Arbeitsbelastung für diese Tabelle verursachen
Wenn eine Operation auf den Primärschlüssel mit ALGORITHM=INPLACE durchgeführt wird, wird obwohl die Daten immer noch kopiert werden, es
ist effizienter als die Verwendung von ALGORITHM=COPY, weil:
? Es ist kein Undo-Logging oder damit verbundenes Redo-Logging erforderlich für ALGORITHM=INPLACE. Diese Operationen fügen
Überschuss für DDL-Anweisungen, die ALGORITHM=COPY verwenden.
? Die Einträge der sekundären Indizes sind vor-sortiert und daher in der Reihenfolge geladen werden kann.
? Der Änderungsbuffer wird nicht verwendet, weil es keine zufälligen-inserts access in die sekundären Indizes.
)

Wie folgender Ausdruck

mysql> Ändern Sie die Tabelle testsort12 Spalte hinzufügen it int nicht null;
Abfrage OK, 0 Zeilen betroffen (6.27 sec)
Datensätze: 0 Duplikate: 0 Warnungen: 0

Ich analysiere das einfach:

2017-08-03T19:46:54.781453Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T19:46:54.781487Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T19:46:54.781948Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:46:54.781990Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T19:46:54.782026Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:46:54.782060Z 3 [Notiz] (----->MDL-AUSGABE) Mdl-Typ ist: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.782096Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:46:54.782175Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T19:46:54.803898Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufgestuft
2017-08-03T19:46:54.804201Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufstufen
2017-08-03T19:46:54.804240Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T19:46:54.804254Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:46:54.804267Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T19:46:54.804280Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:46:54.804293Z 3 [Notiz] (----->MDL-Druck) Mdl-Typ: MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.804306Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T19:46:54.855563Z 3 [Hinweis] ( downgrade_lock)Dieser MDL-Lock wird herabgestuft
2017-08-03T19:46:54.855693Z 3 [Hinweis] (downgrade_lock) auf dieses MDL-Schloss
2017-08-03T19:46:54.855706Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T19:46:54.855717Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:46:54.856053Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T19:46:54.856069Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:46:54.856082Z 3 [Notiz] (----->MDL-AUSGABE) Mdl-Typ ist: MDL_SHARED_UPGRADABLE(SU) 
2017-08-03T19:46:54.856094Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:46:54.856214Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T19:47:00.260166Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufgestuft
2017-08-03T19:47:00.304057Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufstufen
2017-08-03T19:47:00.304090Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T19:47:00.304105Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:47:00.304119Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T19:47:00.304132Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:47:00.304181Z 3 [Notiz] (----->MDL PRINT) Mdl Typ ist:MDL_EXCLUSIVE(X) 
2017-08-03T19:47:00.304196Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:47:00.304211Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T19:47:01.032329Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt! 

Zunächst wird testsort erhalten12auf der Tabelle

2017-08-03T19:46:54.781487 MDL_SHARED_UPGRADABLE(SU) erhalten
2017-08-03T19:46:54.804293 MDL_EXCLUSIVE(X) aufstufen 
2017-08-03T19:46:54.855563 Abstufung MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:47:00.304057 MDL_EXCLUSIVE(X) aufstufen 

Weil无论如何, diese Änderungsoperation ist recht zeitaufwendig, wie wir aus der Zeit sehen2017-08-03T19:46:54Abstufung abgeschlossen bis2017-08-03T19:47:00 in dieser Zeit
Tatsächlich ist das am meisten zeitraubende, tatsächlich ist dies die tatsächliche COPY-Operation, aber dieser Prozess wird im MDL SU-Modus durchgeführt, sodass DML nicht blockiert wird/SELECT-Operationen.
Hier nochmal ein Hinweis: Der sogenannte ONLINE DDL blockiert im COPY-Stadium DML/SELECT-Operationen, sind daher besser, wenn die Datenbank wenig Last hat
Zum Beispiel, wenn es DML gibt, das nicht abgeschlossen wurde oder SELECT nicht abgeschlossen wurde, dann wird SW SR notwendigerweise blockiert und X kann alles blockieren und hat eine hohe Priorität. Dies führt dazu
Das Phänomen ist darauf zurückzuführen, dass DML nicht abgeschlossen wurde und DDL-Operationen blockiert wurden, und DDL-Operationen blockieren alle Operationen, was im Grunde die gesamte Tabelle dieser TABLE betrifft. Für ALGORITHM=COPY andere Teile sind ähnlich, aber im COPY-Stadium wird das SNW-Schloss verwendet. Also schauen wir uns zunächst das SNW-Schloss an

8、MDL_SHARED_NO_WRITE(SNW)

SU kann auf SNW aufgestuft werden und SNW kann auf X aufgestuft werden, wie zuvor erwähnt, verwendet für ALGORITHM=COPY, um die Datenkonsistenz zu schützen.
Sehen wir zunächst seine Kompatibilität

   Anfrage | Genehmigte Anfragen für das Schloss          
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNW    | +  +  +  -  -  -  +  -  -  - |

Man kann sehen, dass SR möglich ist, aber SW nicht, natürlich blockiert dies auch DML(SW), aber SELECT(SR) wird nicht blockiert. Hier habe ich nur den Schlüsselteil gegeben

mysql> Ändern Sie die Tabelle testsort12 Spalte ik hinzufügen int nicht null, ALGORITHM=COPY ;
2017-08-03T20:07:58.413215Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufstufen
2017-08-03T20:07:58.413241Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T20:07:58.413257Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T20:07:58.413273Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T20:07:58.413292Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T20:07:58.413308Z 3 [Notiz] (----->MDL-AUSGABE) Mdl-Typ ist: MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:07:58.413325Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T20:07:58.413341Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T20:08:25.392006Z 3 [Hinweis] (upgrade_shared_lock)Dieses MDL-Schloss wird aufstufen
2017-08-03T20:08:25.392024Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T20:08:25.392086Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T20:08:25.392159Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T20:08:25.392199Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T20:08:25.392214Z 3 [Notiz] (----->MDL PRINT) Mdl Typ ist:MDL_EXCLUSIVE(X) 
2017-08-03T20:08:25.392228Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T20:08:25.392242Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T20:07:58.413308 erhält MDL_SHARED_NO_WRITE(SNW) 
2017-08-03T20:08:25.392006 auf MDL_EXCLUSIVE(X) aktualisiert 

dies2017-08-03T20:07:58.413308bis2017-08-03T20:08:25.392006ist die tatsächliche COPY-Zeit, zu sehen, dass während der gesamten COPY-Zeit nur DML ausgeführt werden kann
und kann nicht SELECT ausführen, ist auch eine wichtige Unterscheidung zwischen ALGORITHM=COPY und ALGORITHM=INPLACE.

9、MDL_SHARED_READ_ONLY(SRO)

wird für das LOCK TABLES READ-Satz verwendet

Kompatibilität wie folgt

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SRO    | +  +  +  -  -  +  +  +  -  - |
blockiert DML(SW), aber SELECT(SR) ist dennoch möglich.
mysql> lock table testsort12 read;
Query OK, 0 Zeilen beeinflusst (0.01 sec)
2017-08-03T21:08:27.267947Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T21:08:27.267979Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T21:08:27.268009Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T21:08:27.268040Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T21:08:27.268070Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T21:08:27.268113Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_READ_ONLY(SRO) 
2017-08-03T21:08:27.268145Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T21:08:27.268175Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

10、MDL_SHARED_NO_READ_WRITE(SNRW)

wird für das LOCK TABLES WRITE-Satz verwendet

Kompatibilität:

    Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   SNRW   | +  +  -  -  -  -  -  -  -  - |

Man kann sehen, dass DML(SW) und SELECT(SR) blockiert sind, nur SH ist noch okay, und man kann auch DESC(SH) ausführen.

mysql> lock table testsort12 write;
Query OK, 0 Zeilen beeinflusst (0.00 sec)
2017-08-03T21:13:07.113347Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T21:13:07.113407Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T21:13:07.113435Z 3 [Notiz] (--->MDL PRINT) Namespace ist:GLOBAL 
2017-08-03T21:13:07.113458Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T21:13:07.113482Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113505Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_STATEMENT 
2017-08-03T21:13:07.113604Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T21:13:07.113637Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T21:13:07.113660Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T21:13:07.113681Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T21:13:07.113703Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist: 
2017-08-03T21:13:07.113725Z 3 [Notiz] (--->MDL PRINT) Namespace ist:SCHEMA 
2017-08-03T21:13:07.113746Z 3 [Notiz] (---->MDL PRINT) Schneller Weg ist:(Y)
2017-08-03T21:13:07.113768Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX) 
2017-08-03T21:13:07.113791Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T21:13:07.113813Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 
2017-08-03T21:13:07.113842Z 3 [Hinweis] (acquire_lock) THIS MDL LOCK wird erfolgreich erlangt!
2017-08-03T21:13:07.113865Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T21:13:07.113887Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T21:13:07.113922Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T21:13:07.113945Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T21:13:07.113975Z 3 [Notiz] (----->MDL PRINT) Mdl type is:MDL_SHARED_NO_READ_WRITE(SNRW) 
2017-08-03T21:13:07.113998Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T21:13:07.114021Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Darüber hinaus benötigt lock table auch IX-Locks auf GLOBAL und SCHEMA, mit anderen Worten, flush tables with read lock; blockiert
lock table testsort12 write; aber lock table testsort12 read, aber es blockiert nicht.

11、MDL_EXCLUSIVE(X)}

Für verschiedene DDL-Operationen, mit dem Kommentar CREATE/DROP/RENAME TABLE-Befehl, tatsächlich sind fast alle DDL mit dieser Sperre verbunden, wie oben analysiert
add column-Befehl, aber die Dauer ist im Allgemeinen kurz.

Kompatibilität:

   Anfrage | Genehmigte Anfragen für Sperre         |
    Typ  | S SH SR SW SWLP SU SRO SNW SNRW X |
   ----------+---------------------------------------------+
   X     | -  -  -  -  -  -  -  -  -  - |

Es gibt keine Überraschungen, die alles blockieren, und alles blockiert alles

Zum Beispiel der vorhin durchgeführte add column-Befehl

2017-08-03T19:46:54.804240Z 3 [Notiz] (>MDL PRINT) Thread id ist 3: 
2017-08-03T19:46:54.804254Z 3 [Notiz] (->MDL PRINT) DB_name ist:test 
2017-08-03T19:46:54.804267Z 3 [Notiz] (-->MDL PRINT) OBJ_name ist:testsort12 
2017-08-03T19:46:54.804280Z 3 [Notiz] (--->MDL PRINT) Namensraum ist:TABELLE 
2017-08-03T19:46:54.804293Z 3 [Notiz] (----->MDL PRINT) Mdl Typ ist:MDL_EXCLUSIVE(X) 
2017-08-03T19:46:54.804306Z 3 [Notiz] (------>MDL PRINT) Mdl Dauer ist:MDL_TRANSACTION 
2017-08-03T19:46:54.804319Z 3 [Notiz] (------->MDL PRINT) Mdl Status ist:LEER 

Sechstes Kapitel, Quellcode-Kommentare

enum enum_mdl_type {
 /*
  Eine Absicht exklusive Metadaten-Sperre. Nur für scoped Sperren verwendet.
  Der Besitzer dieses Typs von Sperre kann upgradable exklusive Sperren auf
  individuelle Objekte.
  Kompatibel mit anderen IX-Sperren, aber inkompatibel mit scoped S und
  X-Sperren.
 */
 MDL_INTENTION_EXCLUSIVE= 0,
 /*
  Ein gemeinsam genutzter Metadaten-Sperre.
  Nur für Fälle zu verwenden, in denen wir nur an den Metadaten des Objekts interessiert sind
  Es gibt keine Absicht, auf Objektdaten zuzugreifen (z.B. für gespeicherte
  routinen oder während der Vorbereitung von vorbereiteten Anweisungen).
  Wir haben auch-dieses Lock-Typ für offene HANDLER zu verwenden, da Lock
  durch diese Anweisung erlangt werden muss mit dem Lock kompatibel sein, der
  durch das LOCK TABLES ... WRITE-Anweisung, d.h. SNRW (Wir können es nicht mit
  S-Lock zu HANDLER ... OPEN-Zeit und ihn auf SR aufzustufen
  Lock für HANDLER ... READ haben, da es das Problem mit dem Bedarf nicht löst
  um DML-Anweisungen abzubrechen, die auf Tabellebene-Lock warten, während sie
  HANDLER in der gleichen Verbindung öffnen).
  um Deadlocks zu vermeiden, die auftreten können, wenn SNRW-Locks aufgestuft werden zu
  X-Lock für die Tabelle, auf der ein aktiver S-Lock besteht, der von
  der abwartet, seine Reihe auf der Tabelle-von dem Thread gehaltenen Lock
  bei der Aktualisierung wir thr_abort_locks_for_thread() verwenden müssen
  Anlage in dieser Situation.
  Dieses Problem tritt nicht für Locks auf gespeicherten Routine auf, da wir nicht
  Für sie SNRW-Locks zu verwenden. Es tritt ebenfalls nicht auf, wenn S-Locks verwendet werden
  期间发生死锁。-在PREPARE调用期间作为表
  级别锁在此
 */
 情况。
 /*
  MDL_SHARED,
  一个高优先级的共享元数据锁。
  用于没有访问对象数据意图的情况(即
  表中的数据)。
  "高优先级"意味着,与其他共享锁不同,它被授予
  忽略对排他锁的挂起请求。适用于
  在仅需要访问元数据而不需要数据的情况下使用,例如当
  由于SH锁与SNRW锁兼容,因此正在填充INFORMATION_SCHEMA表的连接。
  持有SH锁的锁不应尝试获取任何类型的表-级别
  或行-级别锁,因为这可能导致死锁。此外,在
  获取SH锁时,连接不应等待获取任何其他
  资源,因为它可能会导致X锁的饥饿和潜在的
  在将SNW或SNRW升级为X锁时发生死锁(例如,如果
  升级连接保持正在等待的资源()。
 */
 MDL_SHARED_HIGH_PRIO,
 /*
  Eine gemeinsame Metadaten-Sperre für Fälle, in denen eine Leseabsicht
  von der Tabelle.
  Eine Verbindung, die diese Art von Sperre hält, kann Tabellenmetadaten lesen und lesen
  Tabellen Daten (nach dem Erwerben der angemessenen Tabellen- und Zeilen-Ebene Sperren).
  Das bedeutet, dass man nur TL_READ, TL_READ_NO_INSERT und
  ähnliche Tabelle-Ebene Sperren auf der Tabelle, wenn eine SR MDL-Sperre darauf gehalten wird.
  Für Tabellen in SELECTs, Unterabfragen und LOCK TABLE ... READ
  Anweisungen.
 */
 MDL_SHARED_READ,
 /*
  Eine gemeinsame Metadaten-Sperre für Fälle, in denen eine Änderung
  (und nicht nur lesen) Daten in der Tabelle.
  Eine Verbindung, die eine SW-Sperre hält, kann Tabellenmetadaten lesen und ändern oder lesen
  Tabellen Daten (nach dem Erwerben der angemessenen Tabellen- und Zeilen-Ebene Sperren).
  Für Tabellen bestimmt, die durch INSERT, UPDATE, DELETE
  Anweisungen, aber nicht LOCK TABLE ... WRITE oder DDL). Auch von
  SELECT ... FOR UPDATE.
 */
 MDL_SHARED_WRITE,
 /*
  Eine Version der MDL_SHARED_WRITE-Sperre, die eine niedrigere Priorität als
  MDL_SHARED_READ_ONLY-Sperren. Verwendet von DML-Anweisungen, die
  Tische und die Verwendung der LOW_PRIORITY Klausel.
 */
 MDL_SHARED_WRITE_LOW_PRIO,
 /*
  Ein upgradefähiger gemeinsam genommener Metadaten-Sperre, der gleichzeitigige Updates und
  Lesen von Tabellen-Daten kompatibel ist.
  Eine Verbindung, die diese Art von Sperre hält, kann Tabellenmetadaten lesen und lesen
  Tabellen-Daten. Es sollte keine Daten ändern, da dieser Sperre mit
  SRO-Sperren.
  Kann auf SNW, SNRW und X-Sperren upgradet werden. Sobald die SU-Sperre auf X
  oder SNRW-Sperren Datenmodifikationen können frei erfolgen.
  Sollte für die erste Phase von ALTER TABLE verwendet werden.
 */
 MDL_SHARED_UPGRADABLE,
 /*
  Eine gemeinsam genommene Metadaten-Sperre für Fälle, in denen wir Daten aus der Tabelle lesen müssen
  und alle gleichzeitigigen Modifikationen daran blockiert (sowohl Daten als auch Metadaten).
  Wird vom LOCK TABLES READ-Ausdruck verwendet.
 */
 MDL_SHARED_READ_ONLY,
 /*
  Ein upgradefähiger gemeinsam genommener Metadaten-Sperre, der alle Versuche
  Tabellen-Daten, Lesen zu erlauben.
  Eine Verbindung, die diese Art von Sperre hält, kann Tabellenmetadaten lesen und lesen
  Tabellen-Daten.
  Can be upgraded to X metadata lock.
  Beachten Sie, dass dieser Typ von Sperre nicht mit SNRW oder SW
  Schlüsseltypen, den passenden Motor-Leseschlüsselstufen
  (TL_READ* Für MyISAM, sollten für InnoDB gemeinsam genommene Zeitsperren
  contention-free.
  To be used for the first phase of ALTER TABLE, when copying data between
  tables, to allow concurrent SELECTs from the table, but not UPDATEs.
 */
 MDL_SHARED_NO_WRITE,
 /*
  An upgradable shared metadata lock which allows other connections
  to access table metadata, but not data.
  It blocks all attempts to read or update table data, while allowing
  INFORMATION_SCHEMA and SHOW queries.
  A connection holding this kind of lock can read table metadata modify and
  read table data.
  Can be upgraded to X metadata lock.
  To be used for LOCK TABLES WRITE statement.
  Not compatible with any other lock type except S and SH.
 */
 MDL_SHARED_NO_READ_WRITE,
 /*
  An exclusive metadata lock.
  A connection holding this lock can modify both table's metadata and data.
  No other type of metadata lock can be granted while this lock is held.
  To be used for CREATE/DROP/RENAME TABLE statements and for execution of
  certain phases of other DDL statements.
 */
 MDL_EXCLUSIVE,
 /* Dies sollte das Letzte sein!!! */
 MDL_TYPE_END};
/** Dauer des Metadaten-Schreibschutzes. */
enum enum_mdl_duration {
 /**
  Schlüssel mit Anweisungsduration werden automatisch am Ende freigegeben
  des Anweisungs- oder Transaktionsablaufs.
 */
 MDL_STATEMENT= 0,
 /**
  Schlüssel mit Transaktionsdauer werden automatisch am Ende freigegeben
  der Transaktion.
 */
 MDL_TRANSACTION,
 /**
  Schlüssel mit expliziter Dauer überstehen das Ende des Anweisungs- und Transaktionsablaufs.
  Sie müssen explizit durch Aufruf von MDL_context::release_lock() freigegeben werden.
 */
 MDL_EXPLICIT,
 /* Dies sollte das Letzte sein ! */
 MDL_DURATION_END };
/**
  Objektnamensräume.
  Sic: Beim Hinzufügen eines neuen Mitglieds zu diesem Enum stellen Sie sicher, dass Sie
  Aktualisieren Sie das Array m_namespace_to_wait_state_name in mdl.
  Es existieren verschiedene Arten von Objekten in verschiedenen Namensräumen.
   - GLOBAL wird für den globalen Lese-Schutz verwendet.
   - TABLESPACE ist für Tablespaces.
   - SCHEMA ist für Schemata (alias Datenbanken).
   - TABLE ist für Tabellen und Ansichten.
   - FUNCTION ist für gespeicherte Funktionen.
   - PROCEDURE ist für gespeicherte Verfahren.
   - TRIGGER ist für Trigger.
   - EVENT ist für Ereignis-Scheduler-Ereignisse.
   - COMMIT ist für die Aktivierung des globalen Lese-Locks, um Commits zu blockieren.
   - USER_LEVEL_LOCK ist für Benutzer-Ebene Locks.
   - LOCKING_SERVICE ist für das Namensplugin RW-Lock-Dienst
  Beachten Sie, dass obwohl es keine Metadaten-Locks auf Triggern gibt,
  es ist notwendig, für sie einen separaten Namensraum zu haben, da
  MDL_key wird auch außerhalb des MDL-Systems verwendet.
  Notieren Sie auch, dass Anfragen, die auf Benutzer warten-Ebene Locks erhalten besondere
  Behandlung - die Wartezeit wird abgebrochen, wenn die Verbindung zum Client verloren geht.
 */
 enum enum_mdl_namespace { GLOBAL=0,
              TABLESPACE,
              SCHEMA,
              TABLE,
              FUNCTION,
              PROCEDURE,
              TRIGGER,
              EVENT,
              COMMIT,
              USER_LEVEL_LOCK,
              LOCKING_SERVICE,
              BACKUP,
              BINLOG,
              /* Dies sollte das Letzte sein ! */
              NAMESPACE_END };
Möchten Sie auch sehen