高性能的MySQL(1)锁和MVCC
一、MySQL邏輯架構
| 客戶端 | ||
| 鏈接/線程處理 | ||
| 查詢緩存 | 解析器 | 優化器 |
| 存儲引擎 | ||
二、鎖
1、讀寫鎖
讀鎖是共享的,是互相不阻塞的,多個客戶在同一時間讀取同一資源,互補干擾。寫鎖是排他的,會阻塞其他的寫鎖和讀鎖,寫鎖有更高的優先級~
一種提高共享資源并發性的方式就是讓鎖定對象更有選擇性。盡量只鎖定需要修改的部分數據,而不是所有的資源,鎖定的資源越少,系統的并發性更好。
表鎖(table lock)
表鎖是鎖開銷最小的策略,會鎖定整張表,一個用戶對表進行寫操作前,需要先獲得寫鎖,這會阻塞其他用戶對表的所有讀寫操作。舉例:有如下一張表
CREATE TABLE `emp2` (`id` int(11) NOT NULL DEFAULT '0',`name` varchar(100) NOT NULL,`job` varchar(100) NOT NULL,`num1` int(10) DEFAULT NULL,`num2` int(10) DEFAULT NULL,`num3` int(10) DEFAULT NULL,`job_num` int(10) DEFAULT NULL,`d` date DEFAULT NULL,PRIMARY KEY (`id`),KEY `job_num` (`job_num`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;我們在一個終端中加上讀表鎖
然后打開另一個終端,可以讀但不可以寫
直到第一個鏈接釋放鎖之后,才能修改成功。
行級鎖:
行鎖可以最大程度的支持并發,但是鎖的開銷也最大,InnoDB支持行級鎖,在存儲引擎層實現。
死鎖:
兩個或者多個事務在同一資源上互相占用,并請求鎖定對方占用的資源時,導致產生死鎖,比如有如下2個事務
#事務1 start transaction; update tab set col=45 where id = 4; update tab set col=54 where id = 3; commit; #事務2 start transaction; update tab set col=12 where id = 3; update tab set col=18 where id = 4; commit;如果巧合,兩個事務都執行了第一條,更新了一行,同時鎖定了該行數據,接著都嘗試去執行第二條,卻發現被對方鎖定,然后2個事務都等待對方釋放鎖,則陷入死循環。為了解決這問題,數據庫系統實現了各種死鎖檢測和死鎖超時機制。
2、隱式和顯式鎖定
隱式:InnoDB,在執行事務過程中會自動加鎖,除非執行COMMIT或ROLLBACK時鎖會自動釋放。
顯式:可以使用SELECT...LOCK IN SHARE MODE || SELECT...FOR UPDATE生成鎖
三、InnoDB的MVCC(多版本并發控制)
通過在每行記錄的最后保存2個隱藏的列來實現。一個保存行的創建時間,一個保存行的過期時間,其實存的系統版本號。每開始一個新的事務,系統版本號都會遞增。事務開始時刻的系統版本號作為事務的版本號,用來和查詢到的每行記錄的版本號來比較。
SELECT:
InnoDB會根據以下2個條件檢查每行記錄:
a、只查找版本早于當前事務版本的數據行,也就是行的系統版本號小于或等于事務的系統版本號,這樣可以確保事務讀取的行,要么是在事務開始前已經存在的,要么是事務自身插入或修改的。
b、行的刪除版本要么未定義,要么大于當前事務版本號。這樣可以確保事務讀取到的行在事務開始之前未被刪除。
INSERT:
InnoDB為新插入的每一行保存當前系統版本號為行版本號
DELETE:
InnoDB為刪除的每一行保存當前系統版本號作為行的刪除標示。
UPDATE:
InnoDB為插入一行新紀錄,保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為行刪除標示。
保存這2個額外的系統版本號,使大多數讀操作都可以不用枷鎖。這樣數據庫操作簡單,性能也會很好,并且保證只會讀到標準的行。但是需要額外的空間和更多的檢查工作。
總結
以上是生活随笔為你收集整理的高性能的MySQL(1)锁和MVCC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 测试asp.net for Linux的
- 下一篇: 获取汉字拼音的简便方法