表鎖、行鎖和一致性讀——爲什麼我只查一行的語句,也執行這麼慢?

目錄

1、第一類:查詢長時間不返回

(1)等 MDL 鎖

(2)等 flush

(3)等行鎖

2、第二類:查詢慢

(1)掃描行數多,所以執行慢

(2)一致性讀需要進行多次回滾操作


1、第一類:查詢長時間不返回

mysql> select * from t where id=1;

一般碰到這種情況的話,大概率是表 t 被鎖住了。

首先執行一下 show processlist 命令,看看當前語句處於什麼狀態。

(1)等 MDL 鎖

舉例:

原因:即現在有一個線程正在表 t 上請求或者持有 MDL 寫鎖,把 select 語句堵住了。

解決:通過查詢 sys.schema_table_lock_waits 這張表,我們就可以直接找出造成阻塞的 process id,把這個連接用 kill 命令斷開即可。

(2)等 flush

舉例:

原因:有一個 flush tables 命令被別的語句堵住了,然後它又堵住了我們的 select 語句。

現在有一個線程正要對錶 t 做 flush 操作。MySQL 裏面對錶做 flush 操作的用法,一般有以下兩個:

flush tables t with read lock;

flush tables with read lock;

注:這兩個 flush 語句,如果指定表 t 的話,代表的是隻關閉表 t;如果沒有指定具體的表名,則表示關閉 MySQL 裏所有打開的表

(3)等行鎖

舉例:

原因:session A 啓動了事務,佔有寫鎖,還不提交,是導致 session B 被堵住的原因。

解決:查出誰佔用行鎖,kill掉

2、第二類:查詢慢

(1)掃描行數多,所以執行慢

mysql> select * from t where c=50000 limit 1;

由於字段 c 上沒有索引,這個語句只能走 id 主鍵順序掃描,因此需要掃描 5 萬行。

(2)一致性讀需要進行多次回滾操作

只掃描一行,但是執行很慢的語句:“ select * from t where id=1;”執行時間長達 800 毫秒。而“select * from t where id=1 lock in share mode“,執行時掃描行數也是 1 行,執行時間是 0.2 毫秒

結果:爲什麼結果不一致呢?

原因:session B 更新完 100 萬次,生成了 100 萬個回滾日誌 (undo log)。帶 lock in share mode 的 SQL 語句,是當前讀,因此會直接讀到 1000001 這個結果,所以速度很快;而 select * from t where id=1 這個語句,是一致性讀,因此需要從 1000001 開始,依次執行 undo log,執行了 100 萬次以後,纔將 1 這個結果返回。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章