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

想出家的霸天虎發表於2020-10-22

知道的越多,知道的越少

前言

MySQL是世界上最受歡迎的資料庫管理系統之一,其高效、穩定、靈活、可擴充套件性強並且簡單易學,這些特性使其在全球獲得越來越多的開發人員的青睞。
不管是為了程式更高效的執行,還是為了在面試中侃侃而談,亦或是為了在平時的聊天中裝13…
不管是學生,還是即將步入中年危機的worker…
如果不甘於 CURD,那就有必要對MySQL進行稍微全面的學習
本系列旨在記錄本人學習 MySQL 的一些體會,採用問答式記錄形式,便於知識點記憶
獻給未來的自己,望自勉

注:本篇問答基於 MySQL 8.0

正文

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

在這裡插入圖片描述

“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 的併發插入(系統預設開啟併發插入)。可設定三種模式,如下:

在這裡插入圖片描述
PS:圖片描述中的 ‘孔’ = 文中的 ‘空閒塊’

The End !

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

‘呵,還想打持久戰?只要地球還在轉,我就能繼續持久下去’:心裡如是想到
微笑著說:仙女客氣

寫在最後

最近看了很多MySQL鎖相關的文章,依然不知道如何簡單且全面的表達出來。
如果文中有描述錯誤、不易理解的地方,歡迎指正
如果有其他一些好的建議,請聯絡我,謝謝…

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章