mysql數據庫引擎InnoDB和MyISAM的區別

 

InnoDB支持行級鎖和表級鎖(默認行級鎖),支持事務,外部鍵等;大量的insert和update更快等。只有經過索引條件檢索數據,InnoDB 才使用行級鎖,不然,InnoDB 將使用表鎖。mysql

MyISAM是表級鎖,不支持事務,大量的SELECT查詢更快等sql

BDB引擎支持頁級鎖和表級鎖(默認頁級鎖)數據庫

 

行級鎖

行級鎖是 MySQL 中鎖定粒度最細的一種鎖,表示只針對當前操做的行進行加鎖。行級鎖能大大減小數據庫操做的衝突,其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分爲共享鎖和排他鎖。併發

特色性能

開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。spa

表級鎖

表級鎖是 MySQL 中鎖定粒度最大的一種鎖,表示對當前操做的整張表加鎖,它實現簡單,資源消耗較少,被大部分 MySQL 引擎支持。最常使用的 MyISAM 與 InnoDB 都支持表級鎖定。表級鎖定分爲表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)。線程

特色設計

開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的機率最高,併發度最低。code

頁級鎖

頁級鎖是 MySQL 中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以,採起了折衷的頁級鎖,一次鎖定相鄰的一組記錄。BDB 支持頁級鎖。orm

特色

開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。

 

InnoDB 中的行鎖與表鎖

前面提到過,在 InnoDB 引擎中既支持行鎖也支持表鎖,那麼何時會鎖住整張表?何時只鎖住一行呢?

InnoDB 行鎖是經過給索引上的索引項加鎖來實現的,這一點 MySQL 與 Oracle 不一樣,後者是經過在數據塊中對相應數據行加鎖來實現的。InnoDB 這種行鎖實現的特色意味着:只有經過索引條件檢索數據,InnoDB 才使用行級鎖,不然,InnoDB 將使用表鎖。

在實際應用中,要特別注意 InnoDB 行鎖的這一特性,否則的話,可能致使大量的鎖衝突,從而影響併發性能。

  • 在不經過索引條件查詢的時候,InnoDB 確實使用的是表鎖,而不是行鎖。
  • 因爲 MySQL 的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不一樣行的記錄,可是若是是使用相同的索引鍵,是會出現鎖衝突的。應用設計的時候要注意這一點。
  • 當表有多個索引的時候,不一樣的事務可使用不一樣的索引鎖定不一樣的行,另外,不管是使用主鍵索引、惟一索引仍是普通索引,InnoDB 都會使用行鎖來對數據加鎖。
  • 即使在條件中使用了索引字段,可是否使用索引來檢索數據是由 MySQL 經過判斷不一樣的執行計劃的代價來決定的。若是 MySQL 認爲全表掃描效率更高,好比對一些很小的表,它就不會使用索引,這種狀況下 InnoDB 將使用表鎖,而不是行鎖。所以,在分析鎖衝突時,別忘了檢查 SQL 的執行計劃,以確認是否真正使用了索引。

行級鎖與死鎖

MyISAM 中是不會產生死鎖的,由於 MyISAM 老是一次性得到所需的所有鎖,要麼所有知足,要麼所有等待。而在 InnoDB 中,鎖是逐步得到的,就形成了死鎖的可能。

在 MySQL 中,行級鎖並非直接鎖記錄,而是鎖索引。索引分爲主鍵索引和非主鍵索引兩種,若是一條 SQL 語句操做了主鍵索引,MySQL 就會鎖定這條主鍵索引;若是一條 SQL 語句操做了非主鍵索引,MySQL 就會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。 在進行UPDATEDELETE操做時,MySQL 不只鎖定WHERE條件掃描過的全部索引記錄,並且會鎖定相鄰的鍵值,即所謂的next-key locking.

當兩個事務同時執行,一個鎖住了主鍵索引,在等待其餘相關索引;另外一個鎖定了非主鍵索引,在等待主鍵索引。這樣就會發生死鎖。

發生死鎖後,InnoDB 通常均可以檢測到,並使一個事務釋放鎖回退,另外一個獲取鎖完成事務。

避免死鎖的方法

有多種方法能夠避免死鎖,這裏只介紹常見的三種:

  1. 若是不一樣程序會併發存取多個表,儘可能約定以相同的順序訪問表,能夠大大下降發生死鎖的可能性;
  2. 在同一個事務中,儘量作到一次鎖定所須要的全部資源,減小死鎖產生機率;
  3. 對於很是容易產生死鎖的業務部分,能夠嘗試使用升級鎖定顆粒度,經過表級鎖定來減小死鎖產生的機率。

死鎖的解決方案:

一、先查看當前庫的線程狀況:show  full processlist; 目的看先有沒有這在執行的慢sql線程,若是有就kill掉

二、若是沒有,再去查看innodb的事務表INNODB_TRX,看下里面是否有正在鎖定的事務線程,看看ID是否在show full processlist裏面的sleep線程中,若是是,就證實這個sleep的線程事務一直沒有commit或者rollback而是卡住了

  SELECT * FROM information_schema.INNODB_TRX G;若是有就kill掉

 

共享鎖和排他鎖:

一、共享鎖:稱爲讀鎖,簡稱S鎖,顧名思義,共享鎖就是多個事務對於同一數據能夠共享一把鎖,都能訪問到數據,可是隻能讀不能修改。

二、排他鎖:又稱爲寫鎖,簡稱X鎖,顧名思義,排他鎖就是不能與其餘所並存,如一個事務獲取了一個數據行的排他鎖,其餘事務就不能再獲取該行的其餘鎖,包括共享鎖和排他鎖,可是獲取排他鎖的事務是能夠對數據就行讀取和修改

對於共享鎖你們可能很好理解,就是多個事務只能讀數據不能改數據,對於排他鎖你們的理解可能就有些差異,我當初就犯了一個錯誤,覺得排他鎖鎖住一行數據後,其餘事務就不能讀取和修改該行數據,其實不是這樣的。排他鎖指的是一個事務在一行數據加上排他鎖後,其餘事務不能再在其上加其餘的鎖。mysql InnoDB引擎默認的修改數據語句,update,delete,insert都會自動給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型,若是加排他鎖可使用select ...for update語句,加共享鎖可使用select ... lock in share mode語句。因此加過排他鎖的數據行在其餘事務種是不能修改數據的,也不能經過for update和lock in share mode鎖的方式查詢數據,但能夠直接經過select ...from...查詢數據,由於普通查詢沒有任何鎖機制。

 

注意:mysql的update、delete、insert是默認加了排他鎖的,而普通的selete是什麼鎖都沒加,因此普通selete既能查共享鎖的行也能查排他鎖的行

相關文章
相關標籤/搜索