MySQL 加鎖處理分析(三)

備註:上接 MySQL 加鎖處理分析(二)html

3.一條複雜的SQL

 

寫到這裏,其實MySQL的加鎖實現也已經介紹的八八九九。只要將本文上面的分析思路,大部分的SQL,都能分析出其會加哪些鎖。而這裏,再來看一個稍微複雜點的SQL,用於說明MySQL加鎖的另一個邏輯。SQL用例以下:mysql

複雜SQL

如圖中的SQL,會加什麼鎖?假定在Repeatable Read隔離級別下 (Read Committed隔離級別下的加鎖狀況,留給讀者分析。),同時,假設SQL走的是idx_t1_pu索引。sql

 

在詳細分析這條SQL的加鎖狀況前,還須要有一個知識儲備,那就是一個SQL中的where條件如何拆分?具體的介紹,建議閱讀我以前的一篇文章:SQL中的where條件,在數據庫中提取與應用淺析 。在這裏,我直接給出分析後的結果:數據庫

 

  • Index key:pubtime > 1 and puptime < 20。此條件,用於肯定SQL在idx_t1_pu索引上的查詢範圍。併發

     

  • Index Filter:userid = ‘hdc’ 。此條件,能夠在idx_t1_pu索引上進行過濾,但不屬於Index Key。spa

  • Table Filter:comment is not NULL。此條件,在idx_t1_pu索引上沒法過濾,只能在聚簇索引上過濾。.net

 

在分析出SQL where條件的構成以後,再來看看這條SQL的加鎖狀況 (RR隔離級別),以下圖所示:htm

SQL加鎖

從圖中能夠看出,在Repeatable Read隔離級別下,由Index Key所肯定的範圍,被加上了GAP鎖;Index Filter鎖給定的條件 (userid = ‘hdc’)什麼時候過濾,視MySQL的版本而定,在MySQL 5.6版本以前,不支持Index Condition Pushdown(ICP), 所以Index Filter在MySQL Server層過濾,在5.6後支持了Index Condition Pushdown,則在index上過濾。若不支持ICP,不知足Index Filter的記錄,也須要加上記錄X鎖,若支持ICP,則不知足Index Filter的記錄,無需加記錄X鎖 (圖中,用紅色箭頭標出的X鎖,是否要加,視是否支持ICP而定);而Table Filter對應的過濾條件,則在聚簇索引中讀取後,在MySQL Server層面過濾,所以聚簇索引上也須要X鎖。最後,選取出了一條知足條件的記錄[8,hdc,d,5,good],可是加鎖的數量,要遠遠大於知足 條件的記錄數量。blog

 

結論:在Repeatable Read隔離級別下,針對一個複雜的SQL,首先須要提取其where條件。Index Key肯定的範圍,須要加上GAP鎖;Index Filter過濾條件,視MySQL版本是否支持ICP,若支持ICP,則不知足Index Filter的記錄,不加X鎖,不然須要X鎖;Table Filter過濾條件,不管是否知足,都須要加X鎖。索引

 

4.死鎖原理與分析

 

本文前面的部分,基本上已經涵蓋了MySQL/InnoDB全部的加鎖規則。深刻理解MySQL如何加鎖,有兩個比較重要的做用:

 

  • 能夠根據MySQL的加鎖規則,寫出不會發生死鎖的SQL;

     

  • 能夠根據MySQL的加鎖規則,定位出線上產生死鎖的緣由;

下面,來看看兩個死鎖的例子 (一個是兩個Session的兩條SQL產生死鎖;另外一個是兩個Session的一條SQL,產生死鎖):

死鎖用例

死鎖用例2

上面的兩個死鎖用例。第一個很是好理解,也是最多見的死鎖,每一個事務執行兩條SQL,分別持有了一把鎖,而後加另外一把鎖,產生死鎖。

 

第二個用例,雖然每一個Session都只有一條語句,仍舊會產生死鎖。要分析這個死鎖,首先必須用到本文前面提到的MySQL加鎖的規則。針對 Session 1,從name索引出發,讀到的[hdc, 1],[hdc, 6]均知足條件,不只會加name索引上的記錄X鎖,並且會加聚簇索引上的記錄X鎖,加鎖順序爲先[1,hdc,100],後[6,hdc,10]。而 Session 2,從pubtime索引出發,[10,6],[100,1]均知足過濾條件,一樣也會加聚簇索引上的記錄X鎖,加鎖順序爲[6,hdc,10],後 [1,hdc,100]。發現沒有,跟Session 1的加鎖順序正好相反,若是兩個Session剛好都持有了第一把鎖,請求加第二把鎖,死鎖就發生了。

 

結論:死鎖的發生與否,並不在於事務中有多少條SQL語句,死鎖的關鍵在於:兩個(或以上)的Session加鎖的順序不一致。而使用本文上面提到的,分析MySQL每條SQL語句的加鎖規則,分析出每條語句的加鎖順序,而後檢查多個併發SQL間是否存在以相反的順序加鎖的狀況,就能夠分析出各類潛在的死鎖狀況,也能夠分析出線上死鎖發生的緣由。

 

5.總結

 

寫到這兒,本文也告一段落,作一個簡單的總結,要作的徹底掌握MySQL/InnoDB的加鎖規則,甚至是其餘任何數據庫的加鎖規則,須要具有如下的一些知識點:

 

  • 瞭解數據庫的一些基本理論知識:數據的存儲格式 (堆組織表 vs 聚簇索引表);併發控制協議 (MVCC vs Lock-Based CC);Two-Phase Locking;數據庫的隔離級別定義 (Isolation Level);

  • 瞭解SQL自己的執行計劃 (主鍵掃描 vs 惟一鍵掃描 vs 範圍掃描 vs 全表掃描);

  • 瞭解數據庫自己的一些實現細節 (過濾條件提取;Index Condition Pushdown;Semi-Consistent Read);

  • 瞭解死鎖產生的緣由及分析的方法 (加鎖順序不一致;分析每一個SQL的加鎖順序)

 

有了這些知識點,再加上適當的實戰經驗,全面掌控MySQL/InnoDB的加鎖規則,當不在話下。

相關文章
相關標籤/搜索