天天看點

MySql中存儲引擎myisam和innodb的差別

作者:北風濁酒

1.概述

相對其他資料庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支援不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);InnoDB存儲引擎既支援行級鎖( row-level locking),也支援表級鎖,但預設情況下是采用行級鎖。

MySQL主要的兩種鎖的特性可大緻歸納如下:

表級鎖: 開銷小,加鎖快;不會出現死鎖(因為MyISAM會一次性獲得SQL所需的全部鎖);鎖定粒度大,發生鎖沖突的機率最高,并發度最低。

行級鎖: 開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。

考慮上述特點,表級鎖使用與并發性不高,以查詢為主,少量更新的應用,比如小型的web應用;而行級鎖适用于高并發環境下,對事務完整性要求較高的系統,如線上事務處理系統。

2.MyISAM鎖細述

(1). 鎖模式

  MySQL的表級鎖有兩種模式: 表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。

(2). 如何加鎖

  當MyISAM在執行查詢語句時,會自動給涉及到表加讀鎖,在執行更新操作時,會加寫鎖。當然使用者也可以用LOCK TABLE 去顯式的加鎖。顯式的加鎖一般是應用于:需要在一個時間點實作多個表的一緻性讀取,不然的話,可能讀第一個表時,其他表由于還沒進行讀操作,沒有自動加鎖,可能資料會發生改變。并且顯示加鎖後隻能通路加鎖的表,不能通路其他表。

(3). 并發插入

  MyISAM存儲引擎有個系統變量 concurrent_insert,專門用來控制并發插入的行為,可以取 0 , 1 , 2。

  0表示不允許并發插入,1表示表中間沒有删除的行時可以在表末尾插入,2表示總是可以插入。

  一般如果對并發要求比較高的情況下,可以設定為2,總是可以插入,然後定期在資料庫空閑時間對表進行optimize。

(4). 鎖的排程

  需要注意的是,其中讀操作不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;并且當寫鎖和讀鎖同時被申請時,優先獲得寫鎖,這也這正是表級鎖發生鎖沖突機率最高的原因,因為寫鎖可能會一直阻塞讀鎖,是以不适合有大量寫操作的環境下工作。這一問題可以通過設定low-priority-updates這一啟動參數來降低寫的優先級。

  雖然寫鎖優先于讀鎖擷取,但是長時間的查詢操作也可能會讓寫操作餓死,是以盡量避免一條SQL語句執行所有的查詢,應該進行必要的分解。

3.InnoDB鎖細述

  由于InnoDB支援事務,并預設是使用行級鎖,是以InnoDB的鎖問題和MyISAM鎖問題還是有蠻大差别的。

(1). 鎖模式

  共享鎖(S)和排他鎖(X),分别類似于MyISAM的讀鎖和寫鎖。對于 UPDATE、 DELETE 和 INSERT 語句,InnoDB會自動給涉及資料集加排他鎖(X);對于普通 SELECT 語句,InnoDB不會加任何鎖。

(2). 如何加鎖

  可以顯式的加鎖,用lock in share mode 顯式的加共享鎖,用 for update 顯式的加排他鎖。

  需要注意的是,如果線程A加了共享鎖後,線程B對同一個表加了共享鎖,那麼兩個線程需要進行更新操作時會産生死鎖。是以,進行更新操作時最好加排他鎖。

(3). InnoDB行鎖的實作方式——索引加鎖

  這一點與Oracle不同,是以這也意味着(重要):1. 隻有通過索引條件檢索資料時,InnoDB才會使用行級鎖,否則會使用表級鎖。 2. 即使是通路不同行的記錄,如果使用的是相同的索引鍵,會發生鎖沖突。 3. 如果資料表建有多個索引時,可以通過不同的索引鎖定不同的行。

(4). 間隙鎖

  InnoDB支援事務,為了滿足隔離級别的要求,InnoDB有個間隙鎖,當使用範圍查找時,InnoDB會給滿足key範圍要求,但實際并不存在的記錄加鎖。例如:select * from user where id > 100 for updata 會給ID>100的記錄加排他鎖,滿足這個範圍,但不存在的記錄,會加間隙鎖,這樣可以避免幻讀,避免讀取的時候插入滿足條件的記錄。

(5). 隔離級别與鎖

  一般來說,隔離級别越高,加鎖就越嚴格。這樣,産生鎖沖突的機率就越大,一般實際應用中,通過優化應用邏輯,選用 可送出讀 級别就夠了。對于一些确實需要更高隔離級别的事務,再通過set session transaction isolation level+"級别" 來動态改變滿足需求。

4.死鎖

  MyISAM是沒有死鎖問題的,因為他會一次性獲得所有的鎖。

  InnoDB發生死鎖後一般能自動檢測到,并使一個事務釋放鎖并回退,另一個事務獲得鎖,繼續完成事務。

  在應用中,可以通過如下方式來盡可能的避免死鎖:

    (1) 如果不同的程式會并發的存取多個表,應盡量約定以相同的順序來通路表,這樣可以大大降低産生死鎖的機會。

    (2) 在程式以批量方式處理資料時,如果事先對資料排序,保證每個線程按固定的順序來處理記錄,也可以大大的降低出現死鎖的可能。

繼續閱讀