字節面試:MySQL什麼時候 鎖表?如何防止鎖表?

文章很長,且持續更新,建議收藏起來,慢慢讀!瘋狂創客圈總目錄 博客園版 爲您奉上珍貴的學習資源 :

免費贈送 :《尼恩Java面試寶典》 持續更新+ 史上最全 + 面試必備 2000頁+ 面試必備 + 大廠必備 +漲薪必備
免費贈送 :《尼恩技術聖經+高併發系列PDF》 ,幫你 實現技術自由,完成職業升級, 薪酬猛漲!加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷1)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷2)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷3)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領

免費贈送 資源寶庫: Java 必備 百度網盤資源大合集 價值>10000元 加尼恩領取


字節面試:MySQL什麼時候 鎖表?如何防止鎖表?

尼恩特別說明: 尼恩的文章,都會在 《技術自由圈》 公號 發佈, 並且維護最新版本。 如果發現圖片 不可見, 請去 《技術自由圈》 公號 查找

尼恩說在前面

在40歲老架構師 尼恩的讀者交流羣(50+)中,最近有小夥伴拿到了一線企業如 字節、得物、阿里、滴滴、極兔、有贊、希音、百度、網易、美團、螞蟻、得物的面試資格,遇到很多很重要的面試題:

什麼情況下,MySQL會鎖定整個表?

如何減少或避免鎖表?

如何解決提升msyql的性能,避免鎖表?

最近有小夥伴在面試字節,都到了這個的面試題。

小夥伴沒回答好,支支吾吾的說了幾句,面試官不滿意,面試掛了。

所以,尼恩給大家做一下系統化、體系化的梳理,幫大家展示一下大家雄厚的 “技術肌肉”,讓面試官愛到 “不能自已、口水直流”,然後實現”offer直提”。

當然,這道面試題,以及參考答案,也會收入咱們的 《尼恩Java面試寶典PDF》V175版本,供後面的小夥伴參考,提升大家的 3高 架構、設計、開發水平。

《尼恩 架構筆記》《尼恩高併發三部曲》《尼恩Java面試寶典》的PDF,請到文末公號【技術自由圈】獲取

本文的2個重量級作者:

  • 第一重量級作者 Mark(資深架構師,負責寫初稿 )
  • 第二重量級作者 尼恩 (40歲老架構師, 負責提升此文的 技術高度,讓大家有一種 俯視 技術的感覺)

《尼恩Java面試寶典》 是大家 面試的殺手鐗, 此文當最新PDF版本,可以找43歲老架構師尼恩獲取。

![圖片](滴滴一面:MySQL什麼時候 鎖表?MySQL什麼時候 鎖記錄?.assets/640.webp)

Mysql調優的重點目標: 避免鎖表

鎖表會帶來一系列問題,影響數據庫的性能和系統的穩定性。

主要是下面的四個問題: 性能問題、死鎖問題、可用性問題、一致性問題

1. 鎖錶帶來的性能問題

鎖表會阻止其他事務對該表的併發訪問,包括讀操作和寫操作。

鎖表會導致嚴重的性能問題:

  • 系統吞吐量下降:多個事務需要依次等待鎖的釋放,導致系統整體的吞吐量下降。
  • 用戶體驗差:用戶的請求需要長時間等待,導致響應時間變長,影響用戶體驗。

2. 鎖表引發死鎖

在高併發環境下,鎖表更容易導致死鎖的發生。

鎖表會導致嚴重的事務問題:

  • 事務回滾:部分事務被迫回滾,影響數據一致性。
  • 系統複雜性增加:需要數據庫管理系統介入來檢測和解決死鎖問題,增加系統複雜性。

3. 鎖表降低系統可用性

長時間的表鎖定會影響數據庫的可用性,使得應用程序無法及時處理用戶請求。

鎖錶帶來的系統可用性問題:

  • 功能不可用:系統的部分功能無法使用,影響用戶的正常操作。
  • 業務中斷:在嚴重情況下,可能導致整個系統不可用,影響業務連續性。

4. 鎖表引發數據一致性問題

在高併發寫操作場景下,鎖表會導致數據一致性問題。

鎖錶帶來的數據一致性問題:

  • 數據不一致:無法及時更新數據,影響業務邏輯的正確執行。
  • 狀態混亂:例如,訂單狀態更新時,如果表被鎖定,其他更新操作無法及時進行,可能會導致數據狀態不一致。

那麼,什麼情況下導致鎖表? 如何解決鎖表的問題呢?

回顧一下mysql鎖的分類

從操作的粒度可分爲表級鎖、行級鎖和頁級鎖。

1.表級鎖:

每次操作鎖住整張表鎖定粒度大,發生鎖衝突的概率最高,併發度最低

注意: 表級鎖應用在MyISAM、InnoDB、BDB 等存儲引擎中。

表鎖的特點:

  • 開銷小,加鎖快
  • 不會出現死鎖
  • 鎖定粒度大,發生鎖衝突的概率最高,併發度最低

2.行級鎖:

每次操作鎖住一行數據鎖定粒度最小,發生鎖衝突的概率最低,併發度最高

注意:行級鎖應用在InnoDB 存儲引擎中。MyISAM 沒有行級鎖

行鎖的特點:

  • 開銷大,加鎖慢
  • 會出現死鎖
  • 鎖定粒度小,發生鎖衝突的概率最低,併發度最高

3.頁級鎖:

每次鎖定相鄰的一組記錄,鎖定粒度界於表鎖和行鎖之間,加鎖開銷和加鎖時間界於表鎖和行鎖之間,併發度一般。

注意:頁級鎖 應用在BDB 等存儲引擎中。

頁鎖的特點:

  • 開銷和加鎖時間介於表鎖和行鎖之間
  • 會出現死鎖
  • 鎖定粒度介於表鎖和行鎖之間,併發度一般

MySQL 使用頁級鎖的情況相對較少,因爲 MySQL 默認使用的是行級鎖。

但在特定的情況下,MySQL 可能會使用頁級鎖,主要包括以下幾種情況:

  1. 表級鎖定轉換爲頁級鎖定: 當表級鎖無法滿足需求時,MySQL 可能會將表級鎖轉換爲頁級鎖。這通常發生在使用 BDB 存儲引擎時,因爲 BDB 存儲引擎默認使用表級鎖。在某些情況下,MySQL 可能會將表級鎖轉換爲頁級鎖,以提高併發性能。
  2. 隱式鎖定大量行數據: 在某些情況下,如果一次性鎖定了大量行數據,則 MySQL 可能會使用頁級鎖來減少鎖的數量,從而減輕鎖管理的負擔。例如,在使用 BDB 存儲引擎時,如果一次性鎖定了大量行數據,則 MySQL 可能會將表級鎖轉換爲頁級鎖。
  3. DDL 操作: 在執行對錶結構進行修改的 DDL(數據定義語言)操作時,MySQL 可能會使用頁級鎖來鎖定整個表。例如,當執行 ALTER TABLE 操作時,MySQL 可能會鎖定整個表的頁,以防止其他對錶結構的修改和查詢操作。

總的來說,MySQL 使用頁級鎖的情況相對較少,因爲頁級鎖通常會導致鎖的粒度過大,影響併發性能。在設計數據庫和應用程序時,通常會盡量避免使用頁級鎖,而是優先使用行級鎖或其他更細粒度的鎖。

以上內容比較重要,也比較複雜,

具體的視頻講解,請參見《尼恩Java面試寶典》配套視頻。

InnoDB 存儲引擎中的 表鎖和行鎖

對於 MySQL 來說,每種存儲引擎都可以實現自己的鎖策略和鎖粒度,

比如 InnoDB 引擎支持行級鎖和表級鎖,不支持 頁級鎖

下面主要聚焦介紹 InnoDB 存儲引擎中的兩大鎖:

  • 表級鎖
  • 行級鎖。

InnoDB 的表級鎖

表鎖,顧名思義就是對某個表加鎖。

表級鎖可以分爲:表鎖、元數據鎖、意向鎖三種。

表級鎖之一:表鎖

那什麼時候會使用表鎖呢?

一般情況是對應的存儲引擎沒有行級鎖(例如:MyIASM),或者是對應的 SQL 語句沒有匹配到索引。

對於第一種情況而言,因爲對應存儲引擎不支持行鎖,所以只能是使用更粗粒度的鎖來實現,這也比較好理解。

對於第二種情況而言,如果存儲引擎支持行鎖,但對應的 SQL 就沒有使用索引,那麼此時也是會全表掃描,那此時也是會使用表鎖。

例如下面的語句沒有指定查詢列,或者指定了查詢列但是並沒有用到索引,那麼也是會直接鎖定整個表。

情況1:沒有指定查詢列


select * from user; 

情況2:指定查詢列,但是沒有用到索引


select * from user where name = 'zhangsan'; 

上面說的索引,其實是判斷是否會用行級鎖的關鍵。

表級鎖之二:元數據鎖

元數據,指的是我們的表結構這些元數據。

元數據鎖(Metadata Lock)自然是執行 DDL 表結構變更語句時,我們對錶加上的一個鎖了。

那什麼時候會使用元數據鎖這個表級鎖呢?

當我們對一個表做增刪改查操作的時候,會加上 MDL 讀鎖;當我們要對錶結構做變更時,就會加 MDL 寫鎖。

在MySQL中,當對錶進行寫操作(如INSERT、UPDATE、DELETE)時,需要對相關的數據行加鎖以確保數據的一致性和完整性。在某些情況下,MySQL需要鎖定整個表而不是部分行,這種情況下會鎖定整個表,導致其他會話不能訪問表。

1.使用ALTER TABLE、TRUNCATE TABLE等語句對錶進行結構性修改時,MySQL需要鎖定整個表以防止其他會話對錶進行操作。

2.使用LOCK TABLES語句手動鎖定表時,MySQL將鎖定整個表以確保其他會話不能訪問它。

3.在使用MyISAM存儲引擎時,當執行寫操作時,MySQL會對整個表進行加鎖。這是因爲MyISAM使用表級鎖定而不是行級鎖定。

項目中最常見的鎖表問題,都是由於UPDATE語句或者DELETE語句的where條件沒有走索引導致的。因此我們需要在條件字段上加索引,從而將表鎖變爲行鎖。

表級鎖之三:意向鎖

意向鎖,本質上就是空間換時間的產物,是爲了提高行鎖效率的一個東西。

在 InnoDB 中,我們對某條記錄進行鎖定時,爲了提高併發度,通常都只是鎖定這一行記錄,而不是鎖定整個表。

而當我們需要爲整個表加 X 鎖的時候,我們就需要遍歷整個表的記錄,如果每條記錄都沒有被加鎖,纔可以給整個表加 X 鎖。

而這個遍歷過程就很費時間,這時候就有了意向鎖。

意向鎖,其實就是標記這個表有沒有被鎖,如果有某條記錄被鎖住了,那麼就必須獲取該表的意向鎖。

所以當我們需要判斷這個表的記錄有沒有被加鎖時,直接判斷意向鎖就可以了,減少了遍歷的時間,提高了效率,是典型的用空間換時間的做法。

那麼什麼時候會用到意向鎖呢?

很簡單,就是在對錶中的行記錄加鎖的時候,就會用到意向鎖。

InnoDB 存儲引擎支持 多粒度(granular)鎖定,就是說允許事務在行級上的鎖和表級上的鎖同時存在

那麼爲了實現行鎖和表鎖並存,InnoDB 存儲引擎就設計出了 意向鎖(Intention Lock) 這個東西:

Intention locks are table-level locks that indicate which type of lock (shared or exclusive) a transaction requires later for a row in a table.

很好理解:意向鎖是一個表級鎖,其作用就是指明接下來的事務將會用到哪種鎖。

有兩種意向鎖:

  • 意向共享鎖(IS Lock):當事務想要獲得一張表中某幾行的共享鎖行級鎖)時,InnoDB 存儲引擎會自動地先獲取該表的意向共享鎖(表級鎖)
  • 意向排他鎖(IX Lock):當事務想要獲得一張表中某幾行的排他鎖(行級鎖)時,InnoDB 存儲引擎會自動地先獲取該表的意向排他鎖(表級鎖)

各位其實可以直接把 ”意向“ 翻譯成 ”想要“,想要共享鎖、想要排他鎖,你就會發現原來就這東西啊(滑稽)。

意向鎖之間是相互兼容的:

IS 鎖 IX 鎖
IS 鎖 兼容 兼容
IX 鎖 兼容 兼容

但是與表級讀寫鎖之間大部分都是不兼容的:

X 鎖 S 鎖
IS 鎖 不兼容 兼容
IX 鎖 不兼容 不兼容

注意,這裏強調一點:上表中的讀寫鎖指的是表級鎖,意向鎖不會與行級的讀寫鎖互斥!!!

來理解一下爲什麼說意向鎖不會與行級的讀寫鎖互斥。舉個例子,事務 T1、事務 T2、事務 T3 分別想對某張表中的記錄行 r1、r2、r3 進行修改,很普通的併發場景對吧,這三個事務之間並不會發生干擾,所以是可以正常執行的。

這三個事務都會先對這張表加意向寫鎖,因爲意向鎖之間是兼容的嘛,所以這一步沒有任何問題。

那如果意向鎖和行級讀寫鎖互斥的話,豈不是這三個事務都沒法再執行下去了,對吧。

OK,看到這裏,我們來思考兩個問題:

1)爲什麼沒有意向鎖的話,表鎖和行鎖不能共存?

2)意向鎖是如何讓表鎖和行鎖共存的?

首先來看第一個問題,假設行鎖和表鎖能共存,舉個例子:事務 T1 鎖住表中的某一行(行級寫鎖),事務 T2 鎖住整個表(表級寫鎖)。

問題很明顯,既然事務 T1 鎖住了某一行,那麼其他事務就不可能修改這一行。這與 ”事務 T2 鎖住整個表就能修改表中的任意一行“ 形成了衝突。所以,沒有意向鎖的時候,行鎖與表鎖是無法共存的。

再來看第二個問題,有了意向鎖之後,事務 T1 在申請行級寫鎖之前,MySQL 會先自動給事務 T1 申請這張表的意向排他鎖,當表上有意向排他鎖時其他事務申請表級寫鎖會被阻塞,也即事務 T2 申請這張表的寫鎖就會失敗。

以上內容比較重要,也比較複雜,

具體的視頻講解,請參見《尼恩Java面試寶典》配套視頻。

InnoDB 的行級鎖

行級鎖是存儲引擎級別的鎖,需要存儲引擎支持纔有效。

目前 MyISAM 存儲引擎不支持行級鎖,而 Innodb 存儲引擎則支持行級鎖。

而表級鎖,則是 MySQL 層面就支持的鎖。

那麼什麼時候會使用行級鎖呢?

當增刪改查匹配到索引時,Innodb 會使用行級鎖。

如果沒有匹配不到索引,那麼就會直接使用表級鎖。

InnoDB存儲引擎三種行級鎖

InnoDB引擎行鎖是通過對索引數據頁上的記錄加鎖實現的,主要實現算法有 3 種:Record Lock、Gap Lock 和 Next-key Lock,也就是InnoDB的三種行鎖模式。

  • RecordLock鎖(行鎖):鎖定單個行記錄的鎖。(RecordLock鎖 是記錄鎖,RC、RR隔離級別都支持)
  • GapLock鎖:間隙鎖,鎖定索引記錄間隙(不包括記錄本身),確保索引記錄的間隙不變。(GapLock是範圍鎖,RR隔離級別支持。RC隔離級別不支持)
  • Next-key Lock 鎖(臨鍵鎖):記錄鎖和間隙鎖組合,同時鎖住數據,並且鎖住數據前後範圍。(記錄鎖+範圍鎖,RR隔離級別支持。RC隔離級別不支持)

行級鎖之一:記錄鎖(Record Locks)

(1)記錄鎖, 僅僅鎖住索引記錄的一行,在單條索引記錄上加鎖。
(2)record lock鎖住的永遠是索引,而非記錄本身,即使該表上沒有任何索引,那麼innodb會在後臺創建一個隱藏的聚集主鍵索引,那麼鎖住的就是這個隱藏的聚集主鍵索引。

所以說當一條sql沒有走任何索引時,那麼將會在每一條聚合索引後面加X鎖,這個類似於表鎖,但原理上和表鎖應該是完全不同的。

行級鎖之二:間隙鎖(Gap Locks)

(1)區間鎖, 僅僅鎖住一個索引區間(開區間,不包括雙端端點)。
(2)在索引記錄之間的間隙中加鎖,或者是在某一條索引記錄之前或者之後加鎖,並不包括該索引記錄本身。

(3)間隙鎖可用於防止幻讀,保證索引間的不會被插入數據

比如在 100、10000中,間隙鎖的可能值有 (∞, 100),(100, 10000),(10000, ∞),

以上內容比較重要,也比較複雜,

具體的視頻講解,請參見《尼恩Java面試寶典》配套視頻。

行級鎖之三:臨鍵鎖(Next-Key Locks)

(1)record lock + gap lock, 左開右閉區間。

(2)默認情況下,innodb使用next-key locks來鎖定記錄。select … for update
(3)但當查詢的索引含有唯一屬性的時候,Next-Key Lock 會進行優化,將其降級爲Record Lock,即僅鎖住索引本身,不是範圍。
(4)Next-Key Lock在不同的場景中會退化:

在這裏插入圖片描述

比如在 100、10000中,臨鍵鎖(Next-Key Locks)的可能有 (∞, 100],(100, 10000] , 40歲老架構師尼恩提示,這裏的關鍵是左開右閉

在MySQL中,當對錶進行寫操作(如INSERT、UPDATE、DELETE)時,需要對相關的數據行加鎖以確保數據的一致性和完整性。在某些情況下,MySQL需要鎖定整個表而不是部分行,這種情況下會鎖定整個表,導致其他會話不能訪問表。

1.使用ALTER TABLE、TRUNCATE TABLE等語句對錶進行結構性修改時,MySQL需要鎖定整個表以防止其他會話對錶進行操作。

2.使用LOCK TABLES語句手動鎖定表時,MySQL將鎖定整個表以確保其他會話不能訪問它。

3.在使用MyISAM存儲引擎時,當執行寫操作時,MySQL會對整個表進行加鎖。這是因爲MyISAM使用表級鎖定而不是行級鎖定。

InnoDB 如何加鎖?

InnoDB 採用的是兩階段鎖定協議(two-phase locking protocol),意思是:對於每一個事務Transaction,分爲兩個階段

  • 第一階段:增長階段(Growing Phase)

在這個階段,事務可以獲得鎖定,但不能釋放鎖定。事務可以繼續請求並獲得鎖定,直到它達到了其鎖定點(Lock Point),也就是事務獲得最後一個鎖定的時間點。一旦事務進入第二階段,它就不能再獲得新的鎖定。

  • 第二階段:縮減階段(Shrinking Phase)

在這個階段,事務可以釋放已經持有的鎖定,但不能再獲取新的鎖定。這個階段的目的是確保事務不會在已經進入第二階段後再次請求鎖定

兩階段鎖定協議(two-phase locking protocol),有下面的兩個特點:

  • 特點1:即在事務執行過程中,隨時都可以執行加鎖操作,

  • 特點2:但是只有在事務執行 COMMIT 或者 ROLLBACK 的時候纔會釋放鎖,並且所有的鎖是在同一時刻被釋放。

以上內容比較重要,也比較複雜,

具體的視頻講解,請參見《尼恩Java面試寶典》配套視頻。

InnoDB 如何加鎖?從下面三個維度來分開介紹:

第1個維度:InnoDB 如何加意向鎖?

它比較特殊,是由 InnoDB 存儲引擎自己維護的,用戶無法手動操作意向鎖,

在爲數據行加讀寫鎖之前,InnoDB 會先獲取該數據行所在在數據表的對應意向鎖。

第2個維度:InnoDB如何加表級鎖?:

1)隱式鎖定:對於常見的 DDL 語句(如 ALTERCREATE 等),InnoDB 會自動給相應的表加表級鎖

2)顯示鎖定:在執行 SQL 語句時,也可以明確顯示指定對某個表進行加鎖(lock table user read(write)

lock table user read; # 加表級讀鎖
unlock tables; # 釋放表級鎖

第3個維度:InnoDB 如何加行級鎖?:

1)對於常見的 DML 語句(如 UPDATEDELETEINSERT ),InnoDB 會自動給相應的記錄行加寫鎖

2)默認情況下對於普通 SELECT 語句,InnoDB 不會加任何鎖,但是在 Serializable 隔離級別下會加行級讀鎖

上面兩種是隱式鎖定,InnoDB 也支持通過特定的語句進行顯式鎖定,不過這些語句並不屬於 SQL 規範:

3)SELECT * FROM table_name WHERE ... FOR UPDATE,加行級寫鎖

4)SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE,加行級讀鎖

另外,需要注意的是,InnoDB 存儲引擎的行級鎖是基於索引的,也就是說當索引失效或者說根本沒有用索引的時候,行鎖就會升級成表鎖

舉個例子(這裏就以比較典型的索引失效情況 “使用 or" 來舉例),有數據庫如下,id 是主鍵索引:

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
12345

新建兩個事務,先執行事務 T1 的前兩行,也就是不要執行 rollback 也不要 commit:

圖片

這個時候事務 T1 沒有釋放鎖,並且由於索引失效事務 T1 其實是鎖住了整張表,

此時再來執行事務 2,你會發現事務 T2 會卡住,最後超時關閉事務:

圖片

回到面試題:什麼情況下,MySQL會鎖定整個表?

回到字節的面試題的核心:MySQL什麼時候 鎖表?

MySQL會在以下情況下鎖定整個表:

1.對錶進行結構性修改:

當使用ALTER TABLE或TRUNCATE TABLE等語句對錶進行結構性修改時,MySQL需要鎖定整個表以防止其他會話對錶進行操作。

2.手動鎖定表:

使用LOCK TABLES語句手動鎖定表時,MySQL將鎖定整個表以確保其他會話不能訪問它。

3.MyISAM寫操作:

在使用MyISAM存儲引擎時,執行寫操作會導致MySQL對整個表加鎖,

這是因爲MyISAM使用表級鎖定而不是行級鎖定。

4.兩個或多個事務在同時修改一個表時:

事務中包含多條對同一個表進行修改的SQL語句時,該表會被鎖定。

這是因爲MVSQL採用行鎖定機制,但當兩個或多個事務在同時修改一個表時,未使用的修改請求會被放入等待隊列。

5.索引操作:

對一個大表進行索引操作(如新建或刪除索引)時,該表會被鎖定。

索引操作鎖定表的時間與表的大小和結構有關。

6.併發操作:

在一張表中插入大量數據的同時,嘗試在同一時刻進行查詢操作,會導致表被鎖定。

這是因爲查詢和插入操作都需要獲取相應的鎖

7 索引不可用時加鎖操作:

使用SELECT..FOR UPDATE語句進行行級鎖定操作時,如果索引不可用,MySQL可能會升級爲表鎖。

8.索引選擇不恰當:

在某些情況下,如果查詢的索引選擇不恰當,MVSQL可能會升級爲表鎖,尤其是當鎖住的數據量較大時

9.更新和刪除場景,where沒命中索引(最常見場景):

項目中最常見的鎖表問題,都是由於UPDATE/DELETE時, where條件沒有走索引導致的。

當執行UPDATE或DELETE語句且where條件未使用索引時,可能會導致全表掃描並鎖定整個表。

因此我們需要在條件字段上加索引,從而將表鎖變爲行鎖。

以上內容比較重要,也比較複雜,

具體的視頻講解,請參見《尼恩Java面試寶典》配套視頻。

10.查詢場景,索引失效的情況下,行鎖升表鎖

在索引失效的情況下,MySQL會把所有聚集索引記錄和間隙都鎖上,稱之爲鎖表,或叫行鎖升表鎖.

在 MySQL 中,索引對於查詢性能至關重要,但是有些情況下索引可能會失效,從而導致查詢性能下降

以下是一些常見的索引失效原因及其解決方法:

10.1. 使用函數或操作符

  • 原因:在 WHERE 子句中使用函數或操作符(如計算、轉換函數)會導致索引失效。
  • 示例SELECT * FROM table WHERE YEAR(date_column) = 2023;
  • 解決方法:在索引列上避免使用函數或操作符。可以改爲:SELECT * FROM table WHERE date_column BETWEEN '2023-01-01' AND '2023-12-31';

10.2. 模糊查詢

  • 原因:在 LIKE 子句中以通配符開頭的查詢(如 '%abc')會導致索引失效。
  • 示例SELECT * FROM table WHERE column LIKE '%value';
  • 解決方法:避免在 LIKE 中使用前置通配符,可以使用後置通配符:SELECT * FROM table WHERE column LIKE 'value%';

10.3. 不符合最左前綴原則

  • 原因:複合索引必須按照最左前綴原則使用,否則會導致索引失效。
  • 示例:對於索引 (a, b, c),查詢 WHERE b = 1 AND c = 2 會導致索引失效。
  • 解決方法:確保查詢條件按照索引的順序使用,如 WHERE a = 1 AND b = 2 AND c = 3

10.4. 數據類型不一致

  • 原因:查詢條件中的數據類型與索引列的數據類型不一致,會導致索引失效。
  • 示例SELECT * FROM table WHERE varchar_column = 123;
  • 解決方法:確保查詢條件的數據類型與索引列的數據類型一致:SELECT * FROM table WHERE varchar_column = '123';

10.5. 使用 OR 條件

  • 原因:在多個列上使用 OR 條件時,如果其中一個列沒有索引,整個查詢會導致索引失效。
  • 示例SELECT * FROM table WHERE column1 = 1 OR column2 = 2;
  • 解決方法:可以改爲 UNION 查詢以使用索引:SELECT * FROM table WHERE column1 = 1 UNION SELECT * FROM table WHERE column2 = 2;

10.6. 隱式類型轉換

  • 原因:隱式類型轉換會導致索引失效。
  • 示例SELECT * FROM table WHERE varchar_column = 123;
  • 解決方法:顯式轉換查詢條件的數據類型:SELECT * FROM table WHERE varchar_column = '123';

10.7. 範圍條件

  • 原因:在複合索引中,範圍條件(如 <, >, BETWEEN, LIKE)之後的索引列會失效。
  • 示例:對於索引 (a, b),查詢 WHERE a > 1 AND b = 2 會導致索引 b 失效。
  • 解決方法:儘量避免在複合索引中使用範圍條件,如果必須使用,考慮調整索引順序。

10.8. NULL 判斷

  • 原因:在某些情況下,對 NULL 的判斷會導致索引失效。
  • 示例SELECT * FROM table WHERE column IS NULL;
  • 解決方法:確保列上有合適的索引,並且在設計表結構時儘量避免使用 NULL。

10.9. 更新頻繁的列

  • 原因:在頻繁更新的列上建立索引,可能會導致索引的維護成本高,從而影響查詢性能。
  • 解決方法:在設計索引時,儘量避免在頻繁更新的列上建立索引。

10.10. 查詢優化器選擇

  • 原因:有時候查詢優化器可能錯誤地選擇了全表掃描而不是使用索引,特別是在小表或索引列的選擇性不高的情況下。
  • 解決方法:可以使用 FORCE INDEX 強制使用特定索引,或調整查詢語句和索引設計以幫助優化器選擇正確的索引。

通過識別和解決這些索引失效的原因,可以顯著提高 MySQL 查詢的性能。

MySQL會鎖表的場景總結

總之,MVSQL在執行結構性修改、手動鎖定、寫操作、事務處理、索引操作、併發操作、加鎖操作、以及在特定查詢條件下索引失效,都可能需要對錶進行鎖定。

瞭解這些情況,有助於更好地進行MySQL性能優化

回到面試題第二問:如何減少或避免鎖表?

鎖表會對系統性能、數據一致性和用戶體驗產生負面影響,甚至可能引發嚴重的業務中斷和系統崩潰。

因此,避免鎖表是數據庫優化和系統設計中的重要任務。

可以通過優化索引、分解大事務、合理設計表結構、使用適當的事務隔離級別、讀寫分離等方法來減少鎖表問題,提升系統的併發性能和穩定性。

在 MySQL 中避免鎖表問題對於提高數據庫性能和併發性至關重要。

以下是一些調優策略和最佳實踐,以減少或避免鎖表問題:

1. 使用合適的存儲引擎

  • InnoDB:使用支持行級鎖的存儲引擎,如 InnoDB。InnoDB 是 MySQL 的默認存儲引擎,支持行級鎖定和事務,能夠有效減少鎖衝突。
  • 避免使用 MyISAM,因爲它只支持表級鎖定,容易導致鎖表問題。

2. 優化查詢和索引

  • 索引:確保查詢使用適當的索引來減少掃描的行數,從而減少鎖定的範圍和時間。
  • 覆蓋索引:使用覆蓋索引以減少表掃描,提高查詢效率。
  • 優化查詢語句:避免使用複雜的查詢語句,儘量簡化查詢條件,減少鎖定時間。

3. 分解大事務

  • 分解大事務:將大事務分解成多個小事務,以減少單個事務持有鎖的時間,降低鎖衝突的概率。
  • 事務控制:在事務中,儘量減少鎖定時間。儘量避免在事務中進行用戶交互操作。

4. 鎖策略和隔離級別

  • 鎖策略:儘量使用行級鎖定,而不是表級鎖定。確保在需要時顯式地使用合適的鎖策略。
  • 隔離級別:選擇適當的事務隔離級別(如 Read Committed 或 Repeatable Read),以平衡一致性和併發性。儘量避免使用 Serializable 隔離級別,因爲它會導致更多的鎖定和衝突。

5. 分區和分表

  • 表分區:對大表進行分區,以減少每次操作的行數和鎖定範圍,提高併發性。
  • 分表:將數據分佈到多個表中,以減少單個表的負載和鎖定衝突。

6. 避免長時間的鎖定操作

  • 批量操作:將批量操作分成多個小批次,以減少每次操作的鎖定時間。
  • 在線DDL操作:使用 InnoDB 的在線 DDL 功能(例如,ALTER TABLE ... ALGORITHM=INPLACE),以減少對錶的鎖定時間。

7. 監控和分析

  • 監控鎖等待:使用 MySQL 的性能_schema 和相關工具(如 SHOW PROCESSLISTINFORMATION_SCHEMA.INNODB_LOCKSINFORMATION_SCHEMA.INNODB_LOCK_WAITS)監控鎖等待情況。
  • 分析慢查詢:使用 slow query log 分析慢查詢日誌,找出可能導致鎖表的查詢,並進行優化。

8. 讀寫分離

  • 主從複製:通過主從複製實現讀寫分離,將讀操作分散到從庫上,以減輕主庫的負載和鎖定壓力。

9. 使用合適的鎖

  • 顯式鎖定:在需要時顯式地使用合適的鎖定策略(如 SELECT ... FOR UPDATE),但要謹慎使用,避免不必要的長時間鎖定。

10. 業務層優化

  • 批量提交:在業務邏輯中優化批量提交操作,減少鎖衝突。
  • 樂觀鎖定:在業務層使用樂觀鎖定機制,以減少數據庫鎖定衝突。

通過以上策略和最佳實踐,可以有效減少或避免 MySQL 中的鎖表問題,提高數據庫的併發性和性能。

技術自由圈幾個 和MYSQL 有關的核心面試真題

炸裂:MySQL死鎖 是什麼,如何解決?(史上最全)

貝殼面試:MySQL聯合索引,最左匹配原則是什麼?

MVCC學習聖經:一文穿透MySQL MVCC,吊打面試官

字節面試: Mysql爲什麼用B+樹,不用跳錶?

手寫一個跳錶,跪了。。。

上面的核心面試題,一定要掌握,背到滾瓜爛熟、滾瓜爛熟、滾瓜爛熟

更多的核心面試題,請參見5000頁的鴻篇鉅製 :《尼恩Java面試寶典》

說在最後:有問題找老架構取經

MySQL表鎖、行鎖的相關知識: 如果大家能對答如流,如數家珍,基本上 面試官會被你 震驚到、吸引到。

最終,讓面試官愛到 “不能自已、口水直流”。offer, 也就來了。

在面試之前,建議大家系統化的刷一波 5000頁《尼恩Java面試寶典PDF》,裏邊有大量的大廠真題、面試難題、架構難題。很多小夥伴刷完後, 吊打面試官, 大廠橫着走。

在刷題過程中,如果有啥問題,大家可以來 找 40歲老架構師尼恩交流。

另外,如果沒有面試機會,可以找尼恩來改簡歷、做幫扶。

遇到職業難題,找老架構取經, 可以省去太多的折騰,省去太多的彎路。

尼恩指導了大量的小夥伴上岸,前段時間,剛指導一個40歲+被裁小夥伴,拿到了一個年薪100W的offer。

狠狠卷,實現 “offer自由” 很容易的, 前段時間一個武漢的跟着尼恩捲了2年的小夥伴, 在極度嚴寒/痛苦被裁的環境下, offer拿到手軟, 實現真正的 “offer自由” 。

技術自由的實現路徑:

實現你的 架構自由:

喫透8圖1模板,人人可以做架構

10Wqps評論中臺,如何架構?B站是這麼做的!!!

阿里二面:千萬級、億級數據,如何性能優化? 教科書級 答案來了

峯值21WQps、億級DAU,小遊戲《羊了個羊》是怎麼架構的?

100億級訂單怎麼調度,來一個大廠的極品方案

2個大廠 100億級 超大流量 紅包 架構方案

… 更多架構文章,正在添加中

實現你的 響應式 自由:

響應式聖經:10W字,實現Spring響應式編程自由

這是老版本 《Flux、Mono、Reactor 實戰(史上最全)

實現你的 spring cloud 自由:

Spring cloud Alibaba 學習聖經》 PDF

分庫分表 Sharding-JDBC 底層原理、核心實戰(史上最全)

一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之間混亂關係(史上最全)

實現你的 linux 自由:

Linux命令大全:2W多字,一次實現Linux自由

實現你的 網絡 自由:

TCP協議詳解 (史上最全)

網絡三張表:ARP表, MAC表, 路由表,實現你的網絡自由!!

實現你的 分佈式鎖 自由:

Redis分佈式鎖(圖解 - 秒懂 - 史上最全)

Zookeeper 分佈式鎖 - 圖解 - 秒懂

實現你的 王者組件 自由:

隊列之王: Disruptor 原理、架構、源碼 一文穿透

緩存之王:Caffeine 源碼、架構、原理(史上最全,10W字 超級長文)

緩存之王:Caffeine 的使用(史上最全)

Java Agent 探針、字節碼增強 ByteBuddy(史上最全)

實現你的 面試題 自由:

4800頁《尼恩Java面試寶典 》 40個專題

免費獲取11個技術聖經PDF:

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