InnoDB中不一樣SQL語句設置的鎖

鎖定讀(locking read)、更新(UPDATE)或刪除(DELETE)一般會在SQL語句處理過程當中掃描的每一個索引記錄上設置記錄鎖。語句中是否存在排除行的WHERE條件並不重要。InnoDB不記得確切的WHERE條件,而只知道哪一個索引範圍被掃描。這些鎖一般是next-key鎖,它還會阻止在記錄以前插入「間隙」。然而,間隙鎖(gap lock)能夠被顯式禁用,這會致使不使用next-key鎖。數據庫

若是在檢索中使用了二級索引,而且要設置的索引記錄鎖是排它的,則InnoDB也會檢索相應的彙集索引記錄並在它們上設置鎖。性能

執行SQL語句時,若是沒有找到可用的索引,MySQL必須掃描整個表來處理該語句,這樣的話表的每一行都會被鎖定,從而阻塞其餘用戶對錶的全部插入。所以,建立良好的索引很是重要,這樣能夠避免掃描許多沒必要要的行。優化

InnoDB設置特定類型的鎖,以下所示:spa

  • SELECT ... FROM 是一致讀,讀取數據庫快照,除非將事務隔離級別設置爲SERIALIZABLE,不然不設置鎖。對於SERIALIZABLE級別,檢索會在遇到的索引記錄上設置共享的next-key鎖。可是,對於使用惟一索引來搜索惟一行的語句,只須要一個索引記錄鎖。code

  • 對於 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE ,對掃描的行加鎖,並對不符合結果集中包含條件的行(例如,若是它們不知足WHERE子句中給出的條件)釋放鎖。orm

  • SELECT ... LOCK IN SHARE MODE 在全部遇到的索引記錄上設置共享的next-key鎖。可是,對於使用惟一索引來搜索惟一行的語句,只須要一個索引記錄鎖。blog

  • SELECT ... FOR UPDATE 在搜索遇到的每一個記錄上設置排它的next-key鎖。可是,對於使用惟一索引來搜索惟一行的語句,僅須要索引記錄鎖定。索引

  • UPDATE ... WHERE ... 在搜索遇到的每一個記錄上設置排它的next-key鎖。可是,對於使用惟一索引來搜索惟一行的語句,僅須要索引記錄鎖定。事務

  • DELETE FROM ... WHERE ... 在搜索遇到的每一個記錄上設置排它的next-key鎖。可是,對於使用惟一索引來搜索惟一行的語句,僅須要索引記錄鎖定。rem

  • INSERT 在插入的行上設置排他鎖。該鎖是索引記錄鎖,不是next-key鎖(即沒有間隙鎖),而且不會阻止其餘會話插入到插入行以前的間隙中。

舉個例子,假設有一張表t1,結構以下:

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

再假設,有三個會話操做順序以下:

Session 1:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 2:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 1:

ROLLBACK;

首先Session1得到i=1這一行的排它鎖,接下來Session2和Session3因爲主鍵重複只能請求獲取該行的共享鎖,因爲行上已經有排它鎖,所以Session2和Session3請求的共享鎖不能被當即授予。再接着,Session1回滾,行上的排它鎖被釋放,因而Session2和Session3在該行上都持有共享鎖,此時,死鎖發生了,因爲對方持有的共享鎖,任何一方都不能得到該行的排它鎖。

下面這組操做也是相似:

Session 1:

START TRANSACTION; DELETE FROM t1 WHERE i = 1;

Session 2:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 1:

COMMIT;

和前面的狀況相似,Session1提交之後,Session2和Session3請求該行上的共享鎖被當即授予,此時它們再請求獲取排它鎖時就出現死鎖了,由於共享鎖被另外一個事務持有。

補充: 彙集索引與輔助索引

clustered index (譯:彙集索引、聚簇索引)

secondary index (譯:二級索引、輔助索引)

每一個InnoDB表都有一個特殊的索引,稱爲彙集索引,用於存儲行數據。一般,彙集索引與主鍵是同義詞。爲了從查詢、插入和其餘數據庫操做中得到最佳性能,必須瞭解InnoDB如何使用匯集索引來優化每一個表的最多見的查找和DML操做。

Typically, the clustered index is synonymous with the primary key.

一般,「clustered index」 和 「primary key」 是一個意思。

  • 當你在表上定義一個PRIMARY KEY時,InnoDB將它用做彙集索引。爲建立的每一個表定義一個主鍵。若是沒有邏輯惟一的非空列或列集,請添加一個新的自動遞增(auto-increment)列,其值將自動填充。

  • 若是你沒有爲你的表定義一個PRIMARY KEY,則MySQL會在全部鍵列都不爲NULL的狀況下找到第一個惟一索引,而且InnoDB使用它做爲彙集索引。

  • 若是表沒有主鍵或合適的惟一索引,InnoDB會在包含行ID值的合成列上內部生成一個名爲GEN_CLUST_INDEX的隱藏彙集索引

經過彙集索引訪問行很是快,由於索引搜索直接指向包含全部行數據的頁。若是表很大,彙集索引體系結構一般節省磁盤I/O操做。

除了彙集索引以外的全部索引都稱爲二級索引。在InnoDB中,二級索引中的每條記錄都包含該行的主鍵列,以及爲二級索引指定的列。InnoDB使用此主鍵值在彙集索引中搜索行。

若是主鍵很長,則輔助索引將使用更多空間,所以具備主鍵較短是比較有利的。

With the exception of spatial indexes, InnoDB indexes are B-tree data structures. Index records are stored in the leaf pages of their B-tree or R-tree data structure. The default size of an index page is 16KB. Supported sizes are 64KB, 32KB, 16KB (default), 8KB, and 4KB.

相關文章
相關標籤/搜索