《MySQL》高性能的說法:html
爲什麼須要MVCC
mysql
對於事務型的存儲引擎實現,僅僅依賴鎖是不夠的,還須要MVCC(Multiversion Concurrency Control )的幫助,能夠簡單的將MVCC理解成爲一個row lock的一個變種,只是在必要的時候加行鎖。
sql
InnoDB的MVCC實現方式數據庫
每一個事物存儲引擎的MVCC實現方式是不同的,InnoDB的MVCC簡單來說是經過給表添加兩列隱藏列。
數據結構
一列(建立列)存儲行的insert(若是行不存在)時間或者update(若是行已存在)時間,一列存儲行的刪除時間,固然,這裏的時間並不是咱們所說的時分秒,而是系統版本號(system version number),列存儲的SVN是事物開始時刻的SVN,每開始一個新的事物,SVN號遞增。
併發
MVCC只有在隔離級別是READ COMMITED(Oracle默認)和REPEATABLE READ(MySQL默認)兩個隔離級別下工做。性能
如今討論在REPEATABLE READ下的MVCC實現:this
SELECTspa
a. Innodb查找SVN小於等於當前事物的SVN的行,若是是小於,說明行以前就已經存在,若是是等於,說明這行是事物自己修改過的.線程
b.行的刪除時間列要麼爲空(說明該行未被刪除)要麼刪除時間列的SVN大於當前事物的SVN(表示行是在事物開始以後被刪除的).
只有記錄知足以上兩條,纔會被select語句返回!
Insert
插入以後以當前事物的SVN號更新建立列
Delete
刪除以後,用當前SVN更新刪除列
Update
更新建立列爲當前SVN,同時更新刪除列爲update以前的建立列的SVN值
這樣設計的優勢是大部分的讀操做都不用加鎖了,使數據庫操做簡單,性能好,不足之處是增長了存儲開銷,須要額外的維護工做
查閱5.5的官方文檔,關於MVCC的介紹是這樣的:
InnoDB的MVCC是經過保存舊版本的修改信息來實現事物的併發控制和回滾。這些信息以一種數據結構的形式保存在表空間中,這種數據結構就是「rollback segment」回滾段能夠提供兩項功能:回滾,一致性讀。
與MVCC相關的元素
DB_TRX_ID:佔6字節,用來標識最近一次修改(insert|update)行的事物的標識符,至於delete操做,在innodb看來也不過是一次update操做,更新行中的一個特殊位將行表示爲deleted。並不是真正刪除。
DB_ROLL_PTR:佔用7個字節,滾動指針指向回滾段中的對應回滾日誌記錄,如何update一行,那麼改行舊的信息就會被保存到指針所指向的回滾段中。
DB_ROW_ID:該值隨行數的增多而增長,若是是cluster index,會包含這列,其餘索引則不會有這列。
對於回滾段的管理:
Insert Logs:當事物被提交時,所保存的insert 回滾記錄就能夠被刪除
Update Logs:這個日誌不單單在rollback時須要,在一致性讀也須要,因此不能隨便刪除,只有當數據庫所使用的快照中不涉及該日誌記錄,對應的回滾日誌才能夠刪除。
回滾段的管理指導:
常常將一些事務提交,包括哪些只發出一致性讀的事務,不然InnoDB沒法刪除回滾段中的 undo update logs,這將致使回滾段增加過快直到填滿表空間。
在InnoDB中,發出Delete語句以後,改行並不會馬上被物理的從數據庫中刪除,只有當對應的行update undo logs被刪除以後,纔會被物理的刪除(purge)purge操做很快,時間等於delete所用時間。
有個問題:在頻繁的進行小規模的插入和刪除操做,purge線程將會滯後。由於沒法刪除這些被標記爲deleted的行,這會致使表愈來愈大,致使磁盤瓶頸,性能降低。
解決辦法:限制新行的操做,分配更多的資源給purge線程。涉及參數innodb_max_purge_lag
當purge_lags表示有多少通過delete或者update操做被標記爲deleted的行,沒有被purge,若是該值超過了innodb_max_purge_lag值,則delete和insert,update操做將會被掛起。
The InnoDB
transaction system maintains a list of transactions that have index records delete-marked by UPDATE
or DELETE
operations. The length of this list represents the purge_lag
value. When purge_lag
exceedsinnodb_max_purge_lag
, each INSERT
, UPDATE
, and DELETE
operation is delayed by ((purge_lag
/innodb_max_purge_lag
)×10)–5 milliseconds. The delay is computed in the beginning of a purge batch, every ten seconds. The operations are not delayed if purge cannot run because of an old consistent readview that could see the rows to be purged.
root@localhost>show engine innodb status\G ------------ TRANSACTIONS ------------ Trx id counter 9652 Purge done for trx's n:o < 7965 undo n:o < 0 state: running but idle History list length 17 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 0, not started MySQL thread id 13, OS thread handle 0x8effdb70, query id 361 localhost root init show engine innodb status