天天看點

MySQL 原理與優化:意向鎖,IS,IX

MySQL 原理與優化:意向鎖,IS,IX

先來看一種應用場景,當有兩個線程 A和B 分别通路一張表。

線程 A :針對表中的一條語句進行update 操作,假設根據記錄的id 更新記錄,此時開啟的事務會對這條記錄加行鎖。

線程 B:如果需要進行鎖表的操作,例如:lock tables [table_name] read/write,也就是對表加上讀寫鎖。在加表鎖之前需要檢查行記錄是否加鎖,如果有加鎖就需要等待鎖釋放以後再進行表鎖的後續操作。此時檢查行鎖的操作,就需要從表的第一行向下逐一進行,直到最後一行記錄。

大家知道對表進行掃描操作的效率是非常低的,此時就引入了意向鎖。

意向鎖就是避免DML在執行時,加的行鎖和表鎖發生沖突而引入的,使得表鎖不用加茶妹行資料是否加鎖,使用意向鎖來減少表鎖的檢查。

如上圖所示,在引入意向鎖之後按照這個步驟進行加鎖

  1. 線程A 對表中的某條記錄加行鎖。
  2. 同時對表加上意向鎖。
  3. 當線程 B 對表加表鎖的時候,發現線程A 加的意向鎖,會将表鎖與意向鎖進行對比。如果兩鎖互斥:等待意向鎖釋放執行表鎖的操作,如果兩鎖不互斥:就執行表鎖的操作。

按照這個執行步驟,線程B 就不用去對整張表進行全表掃描了。

意向鎖分為兩類:

意向共享鎖:IS,select ... lock in share mode

意向排他鎖:IX,insert 、update、delete、select ... for update

從上面的語句可以看出意向共享鎖主要對應查詢操作,意向排他鎖對應更新操作。

意向鎖與表鎖的互斥情況:

意向共享鎖:與表共享鎖(read)相容,與表鎖排他鎖(write)互斥。

意向排他鎖:與表共享鎖(read)以及排他鎖(write)都互斥。意向鎖之間不會互斥。

意向鎖對記錄進行讀操作的時候,表鎖可以加讀鎖,也就是其他的線程可以讀表,但是不能寫表。當意向鎖對記錄進行寫入操作的時候,表鎖線程不能對表的資料進行讀和寫的操作,需要等到意向排他鎖對應的事務送出以後才能,進行後續操作。

下面來看兩個例子

第一個例子

開啟線程,通過在sql 語句後面加上 lock in share mode,表示對表加上意向共享鎖

begin;

select * from course where id =2 lock in share mode;

通過sql 語句查詢意向鎖的情況

select object_schema, object_name ,index_name, lock_type ,lock_mode, lock_data from performance_schema.data_locks;

MySQL 原理與優化:意向鎖,IS,IX

從上圖可以看到select 語句在record(行)上加了共享鎖(read),在table(表)上加了IS 共享鎖。

打開另外一個用戶端執行如下語句

lock tables course read;

MySQL 原理與優化:意向鎖,IS,IX

上圖可見,此時加鎖是成功的說明意向共享鎖和表共享鎖(read)是相容的。

接着加上表的互斥鎖write

lock tables course write;

發現光标閃動,說明線程阻塞了。因為意向共享鎖和表排他鎖(write)是互斥的

回到第一個事務,将其commit;

commit;

此時 回到第二個用戶端,看到lock tables course write; 語句得以順利執行。

MySQL 原理與優化:意向鎖,IS,IX

第二個例子

開啟一個事務

begin;

update course set name = 'Json' where id =3;

通過sql 語句查詢意向鎖的情況

select object_schema, object_name ,index_name, lock_type ,lock_mode, lock_data from performance_schema.data_locks;

MySQL 原理與優化:意向鎖,IS,IX

從查詢結果來看,針對表course ,update 語句在行鎖上面加了一個排他鎖,在表的級别加上了一個意向排他鎖。

此時切換到第二個用戶端,執行鎖表的操作,執行表共享鎖(read)

lock tables course read;

由于表共享鎖與意向排他鎖有互斥,是以lock 語句光标停留不動,線程阻塞。

接着通過unlock tables;釋放掉這個 read lock

unlock tables;