MySQL行鎖、表鎖、間隙鎖,你都瞭解嗎

前言

咱們前幾篇講了索引是什麼,如何使用explain分析索引使用狀況,如何去優化索引,以及show profiles分析SQL語句執行資源消耗的學習。今天咱們來說講MySQL的各類鎖,這裏存儲引擎咱們使用InnoDB性能

準備工做

建立表 tb\_innodb\_lock

`drop table if exists test_innodb_lock;`
`CREATE TABLE test_innodb_lock (`
 `a INT (11),`
 `b VARCHAR (20)`
`) ENGINE INNODB DEFAULT charset = utf8;`
`insert into test_innodb_lock values (1,'a');`
`insert into test_innodb_lock values (2,'b');`
`insert into test_innodb_lock values (3,'c');`
`insert into test_innodb_lock values (4,'d');`
`insert into test_innodb_lock values (5,'e');`

建立索引

`create index idx_lock_a on test_innodb_lock(a);`
`create index idx_lock_b on test_innodb_lock(b);`

MySQL 各類鎖演示

  • 先將自動提交事務改爲手動提交:set autocommit=0;
  • 咱們啓動兩個會話窗口 A 和 B,模擬一個搶到鎖,一個沒搶到被阻塞住了。

行鎖(寫&讀)

  • A 窗口執行
`update test_innodb_lock set b='a1' where a=1;`

``````
`SELECT * from test_innodb_lock;`

圖片咱們能夠看到 A 窗口能夠看到更新後的結果學習

  • B 窗口執行
`SELECT * from test_innodb_lock;`

圖片咱們能夠看到 B 窗口不能看到更新後的結果,看到的仍是老數據,這是由於 a = 1 的這行記錄被 A 窗口執行的 SQL 語句搶到了鎖,而且沒有執行 commit 提交操做。因此窗口 B 看到的仍是老數據。這就是 MySQL 隔離級別中的"讀已提交"。優化

  • 窗口 A 執行 commit 操做
`COMMIT;`
  • 窗口 B 查詢
`SELECT * from test_innodb_lock;`

圖片這個時候咱們發現窗口 B 已經讀取到最新數據了spa

行鎖(寫&寫)

  • 窗口 A 執行更新 a = 1 的記錄
`update test_innodb_lock set b='a2' where a=1;`

這時候並無 commit 提交,鎖是窗口 A 持有。code

  • 窗口 B 也執行更新 a = 1 的記錄
`update test_innodb_lock set b='a3' where a=1;`

圖片能夠看到,窗口 B 一直處於阻塞狀態,由於窗口 A 尚未執行 commit,還持有鎖。窗口 B 搶不到 a = 1 這行記錄的鎖,因此一直阻塞等待。索引

  • 窗口 A 執行 commit 操做
`COMMIT;`
  • 窗口 B 的變化

圖片能夠看到這個時候窗口 B 已經執行成功了圖片

表鎖

當索引失效的時候,行鎖會升級成表鎖,索引失效的其中一個方法是對索引自動 or 手動的換型。a 字段自己是 integer,咱們加上引號,就變成了 String,這個時候索引就會失效了。事務

  • 窗口 A 更新 a = 1 的記錄
`update test_innodb_lock set b='a4' where a=1 or a=2;`
  • 窗口 B 更新 a = 2 的記錄
`update test_innodb_lock set b='b1' where a=3;`

圖片這個時候發現,雖然窗口 A 和 B 更新的行不同,可是窗口 B 仍是被阻塞住了,就是由於窗口 A 的索引失效,致使行鎖升級成了表鎖,把整個表鎖住了,索引窗口 B 被阻塞了。資源

  • 窗口 A 執行 commit 操做
`COMMIT;`
  • 窗口 B 的變化

圖片能夠看到這個時候窗口 B 已經執行成功了rem

間隙鎖

  • 什麼是間隙鎖

當咱們採用範圍條件查詢數據時,InnoDB 會對這個範圍內的數據進行加鎖。好比有 id 爲:一、三、五、7 的 4 條數據,咱們查找 1-7 範圍的數據。那麼 1-7 都會被加上鎖。二、四、6 也在 1-7 的範圍中,可是不存在這些數據記錄,這些 二、四、6 就被稱爲間隙。

  • 間隙鎖的危害

範圍查找時,會把整個範圍的數據所有鎖定住,即使這個範圍內不存在的一些數據,也會被無辜的鎖定住,好比我要在 一、三、五、7 中插入 2,這個時候 1-7 都被鎖定住了,根本沒法插入 2。在某些場景下會對性能產生很大的影響

  • 間隙鎖演示

咱們先把字段 a 的值修改爲 一、三、五、七、9

  • 窗口 A 更新 a = 1~7 範圍的數據
`update test_innodb_lock set b='b5' where a>1 and a<7;`
  • 窗口 B 在 a = 2 的位置插入數據
`insert into test_innodb_lock values(2, "b6");`

圖片這個時候發現窗口 B 更新 a = 2 的操做一直在等待,由於 1~7 範圍的數據被間隙鎖,鎖住了。只有等窗口 A 執行 commit,窗口 B 的 a = 2 才能更新成功

行鎖分析

  • 執行 SQL 分析命令
`show status like 'innodb_row_lock%';`

圖片

  • Variable\_name 說明
  • Innodb\_row\_lock\_current\_waits:當前正在等待鎖定的數量。
  • Innodb\_row\_lock\_time:從系統啓動到如今鎖定的時長。
  • Innodb\_row\_lock\_time\_avg:每次等待鎖所花平均時間。
  • Innodb\_row\_lock\_time\_max:從系統啓動到如今鎖等待最長的一次所花的時間。
  • Innodb\_row\_lock\_waits:系統啓動後到如今總共等待鎖的次數。

結語

你們能夠根據 Variable\_name 這幾個參數考慮是否要進行優化,若是鎖定時間,鎖定次數過大,那就該考慮優化了。優化手段能夠參考以前索引優化的文章。

IT 老哥

相關文章
相關標籤/搜索