給表新增字段時,發現鎖表了,查看進程,提示Waiting for table metadata lock
,等待鎖釋放;然而蛋疼的是幾分鐘過去了,依然沒有任何的進展,特此記錄下這個問題的定位過程以及MDL的相關背景知識python
看到上面的表現,基本問題就來了mysql
<!-- more -->git
首先須要確認什麼地方加鎖,從mysql出發,應該怎麼定位?github
對於mysql而言,通常來說上鎖和事物時伴生關係,因此咱們的直觀出發點就是查找db當前正在執行的事物sql
-- 查詢當前正在執行的事物的sql SELECT * FROM information_schema.INNODB_TRX;
輸出結果以下,首先拿到事物對應的進程idbash
拿到id以後,則能夠分析對應的進程信息session
-- 查詢進程信息 show processlist -- 查詢全部的進程信息 show full processlist
而後定位到具體的進程async
而後登錄到目標機器,查看端口號對應的進程,經過lsof
命令查看tcp
lsof -i tcp:52951
從圖中能夠看出,是一個python進程的mysql鏈接開啓的事物,進程id爲5436oop
接着查看進程對應的信息
ps aux | grep 5436
這個腳本正是測試aiomysql的python腳本,內容比較簡單
import asyncio import aiomysql loop = asyncio.get_event_loop() @asyncio.coroutine def test_example(): conn = yield from aiomysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='test', loop=loop, autocommit=False) cur = yield from conn.cursor() yield from cur.execute("SELECT * from test_table") print(cur.description) r = yield from cur.fetchall() print(r) yield from cur.close() conn.close() loop.run_until_complete(test_example())
對python不太熟,直接藉助google查一下,發現有一樣的問題
這個問題拋出,在經過with打開鏈接獲取遊標後,執行mysql,可是沒有commit以前,會鎖表,這個期間修改表都會出現等待
下面近給出瞭解答,並無看到更多的深層次的說明,先記錄下,解決辦法就是在建立鏈接池的時候,選擇自動提交方式,而後就不會有這個問題了
pool = await aiomysql.create_pool( host="localhost", user="test", password="test", db="test", autocommit=True, cursorclass=DictCursor, loop=loop)
找到一篇文章說MDL的,推薦詳細閱讀 MySQL表結構變動你不可不知的Metadata Lock詳解
抓一下核心的要點,簡單說一下看完這篇文章以後的樸素理解
MetaData Lock 簡稱爲MDL,簡單來講就是表的元數據鎖;當修改表結構的時候,就須要持有這個鎖
MDL的主要做用只有一點,保護一個正在執行的事物表結構不被修改
有一個原則,MDL是事物級別的,只有事物結束以後纔會釋放,而這裏面說的事物分爲兩類
直接看上面的說明,不太直觀,一個經典的case以下
session1 開啓了一個事物,執行查詢操做;可是如今session2 要刪除表,若是執行成功,那麼session1的第二次查詢就跪了,這樣就違背了事物的原則,全部在5.5版本引入了MDL,來保證在事物執行期間,表結構不被修改
當咱們出現修改表結構,就須要獲取MDL的排他鎖,所以只有這個表沒有事物在執行時,才能獲取成功;當持有獨佔鎖以後,這個表的其餘操做將被阻塞(即不能插入數據,修改數據,也不能開啓事物操做)
所以在執行DDL時,一直出現等待MDL的時候,常見的緣由有下面三個
經過 show processlist看到表上有正在進行的操做(包括讀),此時修改表時也會等待獲取MDL,這種時候解決辦法要麼就是等待執行完畢,要麼就是直接kill掉進程
經過 show processlist沒有找到表上的操做,可是經過information_schema.innodb_trx
發現有未提交的事物,
經過 show processlist 和事物查詢都沒有的狀況下,可能的場景是一個顯示的事物中,對錶的操做出現了異常,雖然事物失敗,可是持有的鎖尚未釋放,也會致使這個緣由
能夠在performance_schema.events_statements_current
表中查詢失敗的語句
前面兩小節,分別說明什麼是MDL(樸素理解爲表的元數據鎖),以及當修改表時出現長時間的等待MDL的緣由分析;正常看完以後,應該會有下面的疑惑
對於MDL的類型,從網上截一張圖
接下來須要分析下不一樣鎖模式對應的sql
屬性 | 含義 | 事例 |
---|---|---|
MDL_INTENTION_EXCLUSIVE(IX) |
意向排他鎖用於global和commit的加鎖。 | truncate table t1; insert into t1 values(3,’abcde’); 會加以下鎖 (GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE)(SCHEMA,MDL_TRANSACTION,MDL_INTENTION_EXCLUSIVE) |
MDL_SHARED(S) |
只訪問元數據 好比表結構,不訪問數據。 | set golbal_read_only =on 加鎖 (GLOBAL,MDL_EXPLICIT,MDL_SHARED) |
MDL_SHARED_HIGH_PRIO(SH) |
用於訪問information_scheam 表,不涉及數據。 |
select * from information_schema.tables;show create table xx; desc xxx; 會加以下鎖: (TABLE,MDL_TRANSACTION,MDL_SHARED_HIGH_PRIO) |
MDL_SHARED_READ(SR) |
訪問表結構而且讀表數據 | select * from t1; lock table t1 read; 會加以下鎖: (TABLE,MDL_TRANSACTION,MDL_SHARE_READ) |
MDL_SHARED_WRITE(SW) |
訪問表結構而且寫表數據 | insert/update/delete/select .. for update 會加以下鎖:(TABLE,MDL_TRANSACTION,MDL_SHARE_WRITE) |
MDL_SHARED_UPGRADABLE(SU) |
是mysql5.6引入的新的metadata lock,能夠說是爲了online ddl 才引入的。特色是容許DML,防止DDL; | alter table/create index/drop index 會加該鎖; 加入下鎖 (TABLE,MDL_TRANSACTION,MDL_SHARED_UPGRADABLE) |
MDL_SHARED_NO_WRITE(SNW) |
可升級鎖,訪問表結構而且讀寫表數據,而且禁止其它事務寫。 | alter table t1 modify c bigint; (非onlineddl) (TABLE,MDL_TRANSACTION,MDL_SHARED_NO_WRITE) |
MDL_SHARED_NO_READ_WRITE(SNRW) |
可升級鎖,訪問表結構而且讀寫表數據,而且禁止其它事務讀寫。 | lock table t1 write; 加鎖 (TABLE,MDL_TRANSACTION,MDL_SHARED_NO_READ_WRITE |
MDL_EXCLUSIVE(X) |
防止其餘線程讀寫元數據 | CREATE/DROP/RENAME TABLE ,其餘online DDL在rename階段也持有X鎖(TABLE,MDL_TRANSACTION,MDL_EXCLUSIVE) |
上面的內容,可能信息量比較大,特別是MDL的鎖分類狀況,很難抓住重點,針對咱們平常接觸中,簡單給出小結
MDL_SW
鎖MDL_SR
鎖幾個簡稱的說明
insert, update, delete
語句select
語句幾個常見疑問解答
相關博文或者問答
一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛
盡信書則不如,已上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
一灰灰blog
知識星球