天天看點

《淺入淺出MySQL》表鎖 行鎖 并發插入

知道的越多,知道的越少

前言

MySQL是世界上最受歡迎的資料庫管理系統之一,其高效、穩定、靈活、可擴充性強并且簡單易學,這些特性使其在全球獲得越來越多的開發人員的青睐。

不管是為了程式更高效的運作,還是為了在面試中侃侃而談,亦或是為了在平時的聊天中裝13…

不管是學生,還是即将步入中年危機的worker…

如果不甘于 CURD,那就有必要對MySQL進行稍微全面的學習

本系列旨在記錄本人學習 MySQL 的一些體會,采用問答式記錄形式,便于知識點記憶

獻給未來的自己,望自勉

注:本篇問答基于 MySQL 8.0

正文

正值酒足飯飽、昏昏欲睡之際。

‘吱呀’,房門傳來一聲輕微的提示,隻見一隻白玉般的纖手推開房門,走進一個少女來。那少女披着一襲輕紗般的白衣,猶似身在煙中霧裡,看來約莫二十六七歲年紀,除了一頭黑發之外,全身雪白,面容秀美絕俗,隻是肌膚間少了一層血色,顯得蒼白異常…

《淺入淺出MySQL》表鎖 行鎖 并發插入

“hello小帥哥,我是你的面試官 Siri,聽之前面試你的同僚說你對MySQL有一些了解,那我們接下來就聊聊 MySQL吧

鎖是什麼,為什麼需要鎖

千萬别被面試官的外表打亂了氣息。若無法集中注意力,可氣沉丹田,在心中默念“觀自在菩薩,行深般若bai波羅蜜多時,照見五蘊皆空,度一切苦厄。舍利子,色不異空,空不異色,色即是空,空即是色…”

鎖:本質上其實就是一種并發控制的手段(機制)

在多使用者(并發)環境中,在同一時間可能會有多個使用者操作同一條記錄,這會産生沖突(如:更新丢失)。為了解決這些并發帶來的問題, 是以引入并發控制機制(鎖)。

注:鎖的各種 操作(包括加鎖、檢測鎖、釋放鎖、…)都會消耗 資源(CPU、記憶體、資料、…)

了解MySQL 行鎖(行級鎖定) 和 表鎖(表級鎖定)嗎?分别有哪些存儲引擎支援

MySQL 對 InnoDB 表使用行鎖,以支援多個會話同時進行寫通路,使其适合多使用者、高并發和OLTP應用程式。(自動行級鎖定使這些表适合于存儲最重要資料的最繁忙的資料庫,同時也簡化了應用程式邏輯,因為不需要對表進行鎖定和解鎖。是以,InnoDB存儲引擎是MySQL的預設存儲引擎)

除了InnoDB,MySQL對所有其他存儲引擎都使用表鎖,每次隻允許一個會話更新這些表。這種鎖定級别使得這些存儲引擎更适合于隻讀、讀多寫少或單使用者應用程式。

注:InnoDB支援多種粒度鎖定,允許行鎖和表鎖并存(話外音:InnoDB支援表鎖)

MySQL授予表讀鎖的流程

答:查詢表上是否有寫鎖,以及該表的寫鎖隊列是否有寫鎖請求。如果都沒有,則在其上放置一個讀鎖。否則,将讀鎖請求放入讀鎖隊列中。

話外音:讀鎖和讀鎖相容,也就是說,可以同時對同一個表加多個讀鎖

MySQL授予表寫鎖的流程

答:如果表上沒有鎖,則在其上放置一個寫鎖。否則,将鎖定請求放入寫鎖隊列中。

注:寫鎖和其他鎖都不相容,也就是說,如果一個表被加了一個寫鎖,則不能在該表上再加其他鎖(包括讀鎖和寫鎖)。其他鎖請求進入相應的請求隊列

當一個表上的鎖釋放時,如果同時有讀鎖和寫鎖請求,MySQL會怎麼辦呢?

MySQL預設表更新比表檢索具有更高的優先級。是以,當一個表上的鎖被釋放時,總是優先處理寫鎖隊列中的請求(優先給該表加寫鎖),然後對讀鎖隊列中的請求可用。

這樣(寫鎖優先)有什麼好處和缺點呢?

這確定了即使在表有大量查詢操作時,也能對表進行更新操作。但是,如果一個表有很多更新(寫鎖隊列一直有請求),那麼SELECT語句将等待,直到所有更新請求處理完畢。

讀寫優先級可以更改嗎?

答曰:當然可以,通過設定MySQL伺服器系統變量 low_priority_updates = 1 ,可以使表檢索的優先級高于表更新

注:這個變量隻影響僅支援表級鎖的存儲引擎(如MyISAM、MEMORY和MERGE)。【畫外音:這個設定影響不到InnoDB】

分别說說表鎖和行鎖的優缺點及适用場景

行鎖的優點:

1.當不同的會話通路不同的行時,鎖沖突減少。(意味着支援更高的并發)

2.復原更改較少。(InnoDB會自動檢測死鎖條件并復原一個受影響的事務)

3.可以長時間鎖定單個行

表級鎖定的優點:

1.所需的記憶體相對較少(行鎖需要每一行或每組被鎖行的記憶體)

2.在對表資料進行範圍操作時(比如:同時修改多條資料),速度更快,因為僅涉及一個鎖。

3.如果你經常對大部分資料進行分組(group by)操作,或者必須頻繁地掃描整個表,則表鎖速度更快

4.不會出現死鎖(存儲引擎始終在查詢開始時一次請求所有需要的鎖并始終以相同順序鎖定表)

注:行鎖的優點則是表鎖的缺點,反之亦然

怎麼分析表鎖争用情況呢?

可以通過檢查 Table_locks_immediate 和 Table_locks_waited 狀态變量來分析表鎖争用情況。【如果你的系統有性能問題, 恰好Table_locks_waited 的值又很高。應該考慮首先優化查詢,然後拆分一個或多個表或使用複制】

Table_locks_immediate:可以立即授予對表鎖定的請求的次數

Table_locks_waited:無法立即授予對表鎖定的請求,需要等待的次數

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited    | 15324   |
+-----------------------+---------+
           
MyISAM并發插入有了解嗎?

如果一個MyISAM表的資料檔案沒有 空閑塊 (在表資料中間删除行資料産生),則允許查詢和插入語句并發執行。 如果檔案中間有空閑塊,則并發插入會被禁用,但是當所有空閑塊都填充有新資料時,它又會自動重新啟用。

并發插入如何設定?

通過設定MySQL伺服器系統變量 concurrent_insert,開啟或關閉 MyISAM 的并發插入(系統預設開啟并發插入)。可設定三種模式,如下:

《淺入淺出MySQL》表鎖 行鎖 并發插入

PS:圖檔描述中的 ‘孔’ = 文中的 ‘空閑塊’

The End !

‘小帥哥,來先喝杯水,咱們再繼續’

‘呵,還想打持久戰?隻要地球還在轉,我就能繼續持久下去’:心裡如是想到

微笑着說:仙女客氣

寫在最後

最近看了很多MySQL鎖相關的文章,依然不知道如何簡單且全面的表達出來。

如果文中有描述錯誤、不易了解的地方,歡迎指正

如果有其他一些好的建議,請聯系我,謝謝…