InnoDB引擎——6.鎖篇
InnoDB引擎——6.鎖篇
行級鎖神話——行級鎖總會增加開銷
實際上,只有當實現本身會增加開銷時,行級鎖才會增加開銷,InnoDB儲存引擎不需要鎖升級,因為一個鎖和多個鎖的開銷是相同的。如何理解?
MyISAM是表鎖,資料庫中lock和latch都是鎖,
latch更輕量,latch又分為mutex(互斥量)和rwlock(讀寫鎖),注意!沒有通常死鎖檢查機制,lock物件是事物,用來鎖定資料庫物件(表,頁,行),lock在提交和回滾後釋放,是有死鎖機智的。另外latch存在於每個資料結構的物件中,而lock存在於Lock Manager的雜湊表中。
兩種標準的行級鎖:(1)共享鎖(S Lock),讀鎖 (2)排他鎖(X Lock),寫鎖
意向鎖(IX)就是將鎖定物件分為多個層次,意味著事物更希望在更細粒度上進行加鎖。意向鎖為表級別的鎖:
意向共享鎖(IS Lock):事物想獲得一張表某幾行的共享鎖
意向排他鎖(IX lock):事物想獲得一張表某幾行的排他鎖
意向鎖不會阻塞除全表掃描以外的任何請求,因為InnoDB支援的是行級別的鎖。
監控當前事物分析鎖問題的三張表:INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS
(待更新)
一致性非鎖定讀:是指利用多版本控制來讀取當前執行時間資料庫中行的資料(並不是在每個事物隔離級別都採用非鎖定的一致性讀),在事物隔離級別為READ COMMITTED(1)和REPEATABLE READ(2)下使用非鎖定一致性讀,但是在(1)下,讀到的是最新的一份快照資料,在(2)下,讀到的是事物開始的版本。
對於READ COMMITTED的事物隔離級別而言,違反了隔離性
一致性鎖定讀:即使對SELECT操作要求更高,有兩種方式(1)SELECT …FOR UPDATE 表示對讀取的行加一個X鎖(2)SELECT…LOCK IN SHARE MODE 補充:這兩個必須在一個事物中(因為上述的都是在隔離級別裡探討的),務必加上BEGIN,START TRANSACTION或者SET AUTOCOMMIT=0
自增長與鎖:自增長AUTO-INC Locking是一種特殊的表鎖機制,為了提高效能,在完成自增長的SQL語句後就釋放了,新的機制利用innodb_autoinc_lock_mode來控制自增長模式,預設值為1.(有0,1,2:最開始的0是為了相容的),在InnoDB儲存引擎中,自增長的列必須是索引,同時必須是索引的第一列,不然會報錯。
外來鍵和鎖:外來鍵主要用於引用完整性的約束檢查
鎖的演算法:
行鎖的3種演算法:
(1)Record Lock:單個行記錄上的鎖
(2)Gap Lock:間隙鎖,鎖定一個範圍,不包括記錄本身(但是會產生Phantom Problem(幻像問題) ),關閉gap lock 就是隔離級別設為READ COMMITTED
(3)Next-Key Lock :Gap Lock+Record Lock鎖定一個範圍,並且鎖定記錄本身。
當查詢的索引有唯一性時,InnoDB儲存引擎會對Next-key Lock進行優化,將其降級為Record Lock,只鎖住索引本身,而不是範圍,來提高併發性。如果不唯一(即輔助索引),還會對下一個鍵值加上gap lock
對於唯一鍵值的鎖定,Next-Key Lock降級為Record Lock僅存在於查詢所有的唯一索隱列。若唯一索引由多個列組成,而查詢僅是查詢多個唯一索引列中的其中一個,那麼查詢其實是range型別的查詢,而不是point型別查詢,故InnoDB儲存引擎依然使用Next-Key Lock進行鎖定
解決Phantom Problem(幻像問題) :在同一事物下,連續執行兩次同樣的SQL語句可能導致不同的結果,第二次的SQL語句可能會返回之前不存在的行。
鎖問題:
(1)髒讀:在不同事物下,當前事物可以讀到另外事物未提交的資料,簡單來說就是可以讀到髒資料(不常發生),在一些特殊情景需要READ COMMITTED,比如replication環境中的slave節點,並且在該slave上的查詢並不需要特別精確的返回值。
(2)不可重複讀:一個事物內多次讀取同一個資料集合。在這個事物還沒有結束時,另外一個事物也訪問了該同一資料集合,並做了一些DML操作,所以兩次讀到資料不一樣。髒讀是讀到未提交的資料,而不可重複讀讀到的是已經提交的資料。一般來說,不可重複讀的問題是可以接受的。InnoDB儲存引擎的預設事物隔離級別是READ REPEATABLE,採用Next-Key Lock(左開右閉)演算法,避免了不可重複讀的現象。
(3)丟失更新:是另一個鎖導致的問題,簡單來說就是一個事物的更新操作會被另一個事物的更新操作所覆蓋,從而導致資料的不一致。要避免丟失更新發生,需要讓事物在這種情況下的操作變成序列化,不是並行操作。
阻塞:阻塞並不是一件壞事,其實是為了確保事物可以併發且可以正常執行。
死鎖:
(1)死鎖最簡單的方式解決方法是超時,一個事物回滾,一個事物繼續執行,根據FIFO順序選擇回滾物件,但超時的事物所佔權重比較大,就不太合適。
**死鎖檢測機制:**wati-for graph(等待圖)——要求資料庫儲存以下兩種資訊,(1)鎖的資訊連結串列(2)事物的等待連結串列
鎖升級:Microsoft SQL Server資料庫中會有鎖升級,粒度降低,認為鎖是一種稀有資源,但是InnoDB認為不存在鎖升級問題,站在事物的角度認為一個書屋鎖住了頁中的一個記錄還是多個,其開銷都是一致的。(採用點陣圖的方式)
小結:需要學會通過一些命令和資料字典來檢視事物鎖住了哪些資源,不然永遠不知道發生了什麼,可能只是認為MySQL資料庫有時會阻塞而已。