mvcc(multi-version concurrency control)即多版本併發控制,是通過儲存資料在某個時間點的快照來實現的。它使得大部分支援行鎖的事務引擎,不再單純的使用行鎖來進行資料庫的併發控制,取而代之的是,把資料庫的行鎖與行的多個版本結合起來,只需要很小的開銷,就可以實現非鎖定讀,從而大大提高資料庫系統的併發效能.
mysql的大多數事務型(如innodb,falcon等)儲存引擎實現的都不是簡單的行級鎖。基於提公升併發效能的考慮,他們一般都同時實現了mvcc。當前不僅僅是mysql,其它資料庫系統(如oracle,postgresql)也都實現了mvcc。值得注意的是mvcc並沒有乙個統一的實現標準,所以不同的資料庫,不同的儲存引擎的實現都不盡相同。
innodb的mvcc是通過在每行記錄後面儲存2個隱藏的列來實現的,一列儲存了行建立時間,一列儲存了行過期時間(或刪除時間)。但它們都儲存的是系統版本號。
一般概念上的mvcc是通過在row record上隱式的增加兩個版本號(建立版本號和刪除版本號)欄位來記錄資料的建立時間和刪除時間。新增記錄時,建立版本號填入當前事務的事務號,刪除版本號置空;刪除記錄時,將記錄標記為刪除狀態,並將當前事務號填入刪除版本號;當進行更新記錄操作時,則是先將舊記錄標記為刪除(並填入刪除版本號),而後在插入一天新的記錄,建立版本號填入當前事務號。這樣在同乙個事務中,不管期間有多少個其它併發事務對其查詢的記錄做過任何操作,都可以通過將查詢出的所有記錄進行版本號過濾(過濾掉建立版本號和刪除版本號大於和小於當前事務號的記錄),得到與事務開啟時一致的查詢結果。通過mvcc,減少了對資料加鎖的操作,減小效能開銷,大大提高了資料庫的事務併發能力。
最早的資料庫系統,只有讀讀之間可以併發,讀寫,寫讀,寫寫都要阻塞。引入多版本之後,只有寫寫之間相互阻塞,其他三種操作都可以並行,這樣大幅度提高了innodb的併發度
mvcc最大的作用是: 實現了非阻塞的讀操作,讀不加鎖,讀寫不衝突。mysql的mvcc 只在 read committed 和 repeatable read 2個隔離級別下工作.
在mvcc的機制下,mysql innodb(預設隔離級別)的增刪改查變成了如下模式:
select:
對於select語句,只有同時滿足了下面兩個條件的行,才能被返回:
insert:
delete:
update:
注意: 上面的讀取方式只在innodb預設隔離級別下工作,其它的隔離級別會有很大的差異,稍後會看到.
什麼是多版本併發控制呢 ?其實就是在每一行記錄的後面增加兩個隱藏列,記錄建立版本號和刪除版本號,
而每乙個事務在啟動的時候,都有乙個唯一的遞增的版本號。
1、在插入操作時 : 記錄的建立版本號就是事務版本號。
比如我插入一條記錄, 事務id 假設是1 ,那麼記錄如下:也就是說,建立版本號就是事務版本號。
idname
create version
delete version
1test
12、在更新操作的時候,採用的是先標記舊的那行記錄為已刪除,並且刪除版本號是事務版本號,然後插入一行新的記錄的方式。
比如,針對上面那行記錄,事務id為2 要把name欄位更新
update table set name= 'new_value' where id=1;
id
name
create version
delete version
1test12
1new_value
23、刪除操作的時候,就把事務版本號作為刪除版本號。比如
delete from table where id=1;
id
name
create version
delete version
1new_value23
4、查詢操作:
從上面的描述可以看到,在查詢時要符合以下兩個條件的記錄才能被事務查詢出來:
這樣就保證了各個事務互不影響。從這裡也可以體會到一種提高系統效能的思路,就是:
通過版本號來減少鎖的爭用。
undo log 是為了實現事務的原子性,在mysql
資料庫innodb儲存引擎中,還用undo log來實現多版本併發控制(簡稱:mvcc)。
- 用undo log實現原子性和持久化的事務的簡化過程
假設有a、b兩個資料,值分別為1,2。
這裡有乙個隱含的前提條件:『資料都是先讀到記憶體中,然後修改記憶體中的資料,最後將資料寫回磁碟』。
之所以能同時保證原子性和持久化,是因為以下特點:
缺陷:每個事務提交前將資料和undo log寫入磁碟,這樣會導致大量的磁碟io,因此效能很低。
改善:如果能夠將資料快取一段時間,就能減少io提高效能。但是這樣就會喪失事務的永續性。因此引入了另外一
種機制來實現持久化,即redo log.
當資料庫對資料做修改的時候,需要把資料頁從磁碟讀到buffer pool中,然後在buffer pool中進行修改,那麼這個時候buffer pool中的資料頁就與磁碟上的資料頁內容不一致,稱buffer pool的資料頁為dirty page 髒資料,如果這個時候發生非正常的db服務重啟,那麼這些資料還沒在記憶體,並沒有同步到磁碟檔案中(注意,同步到磁碟檔案是個隨機io),也就是會發生資料丟失,如果這個時候,能夠在有乙個檔案,當buffer pool 中的data page變更結束後,把相應修改記錄記錄到這個檔案(注意,記錄日誌是順序io),那麼當db服務發生crash的情況,恢復db的時候,也可以根據這個檔案的記錄內容,重新應用到磁碟檔案,資料保持一致。
這個檔案就是redo log ,用於記錄 資料修改後的記錄,順序記錄。它可以帶來這些好處:
1 為什麼select count(*)在myisam表上很快,而在innodb的表上很慢?
因為innodb採用了mvcc技術,對於相同的行,可能同時存在多個版本,innodb必須根據查詢的時間來過濾掉一些行,才能得出結果,必然要執行全表掃瞄,而全表掃瞄是非常耗時的.對於myisam的表,任何行都只有乙個版本,mysql甚至不需要掃瞄就可以直接返回精確的統計結果,我們用explain也可以看到,對於myisam的表,執行select count(*)的時候,mysql顯示」 select tables optimized away」,查詢直接被優化了;而對於innodb的表,可能是全表掃瞄,也可能是」using index」,總之,速度肯定會比myisam的表慢很多.
2 我的資料庫只是頻繁更新,沒有插入新資料,但是為什麼表空間占用會越來越大?
如果你在資料庫中執行了大事務, innodb就會把被修改資料的前映像存放到稱為回滾段的公共表空間中,而且對於索引和表中的行的多個版本,如果innodb來不及purge,或者這些行因為要提供一致讀而不能被purge,就會占用越來越多的空間,甚至有可能短時間撐爆你的硬碟.所以應用程式中需要合理控制事務的大小.
3 能禁用mvcc嗎?
禁用mvcc可以降低innodb引擎的開銷,而同時innodb又可以支援外來鍵約束,可以實現自動恢復.mvcc本身不支援read uncommitted等級,所以可以通過設定transaction_isolation = read uncommitted 來禁用mvcc.但是任何改變innodb預設隔離等級的操作,都會起到innodb_locks_unsafe_for_binlog=off類似的效果,這會導致諸如insert into t select * from t_src 之類的語句不再給源表t_src加鎖,也不再使用innodb的間隙鎖,從而產生幻讀,直接導致binlog中記錄的sql語句不能正確的序列化,從而主從資料庫的資料不再一致,而且基於binlog的增量備份也不再有效.所以除非不需要記錄binlog,否則別這麼做.當然我們可以這樣做來優化從庫的效能,因為從庫不需要記錄binlog.
4 何時使用char型別,何時使用varchar型別的列?
在使用myisam引擎的情況下,定長表雖然可能占用較多的儲存空間,但是它會加快檢索和全表掃瞄的速度,此時適合選用char的列,而對於表中的變長的列,可以採用分表的方法把變長的列拆分出去,提高定長表的檢索效能.而如果使用的是innodb的引擎,由於innodb的mvcc策略的實施,char資料型別相對於varchar型別幾乎沒有任何優勢,反而varchar列可能節省更多的儲存空間,建議使用varchar資料型別.
多版本併發控制(MVCC)
mysql的大多數事務性儲存引擎 如innodb 實現的都不是簡單的行級鎖。基於提公升併發效能的考慮,它們一般都同時實現了多版本併發控制 mvcc 可以認為mvcc是行級鎖的乙個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要...
多版本併發控制MVCC
大多數mysql的事務性儲存引擎,例如innodb.falcon 和pbxt,不是簡單地使用行加鎖的機制,而是選用一種叫做 多版本併發控制 mvcc,mutiversion concurrency control 的技術,和行加鎖機制關聯使用,以應對更多的併發處理問題。mvcc不是mysql獨有的技...
MVCC(多版本併發控制)
mvcc是資料庫鎖策略的一種實現的統稱。使用mvcc可以在大多數情況下避免加鎖的操作,為服務帶來更好的效率。mysql的大多數事務型儲存引擎實現的都不是簡單的行級鎖。基於提公升併發效能的考慮,它們一般都同時實現了多版本併發控制 mvcc 不同的資料庫實現mvcc的機制不盡相同。我們可以粗略的認為mv...