一、MySQL邏輯架構
第一層的服務不是MySQL獨有的,大多數是基於網絡的客戶端/服務端的工具,如連接處理、授權認證、安全等等。
第二層就是MySQL的核心功能,包括查詢解析、分析、優化、緩存以及所有的內置函數,所有的跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖等。
第三層包含了存儲引擎,主要負責MySQL中數據的存儲和提取。
1.連接管理與安全
每個客戶端連接都會伺服器進程中擁有一個線程,這個連接的查詢只會在這個單獨的線程中執行,該線程只能輪流在某個CPU核心或者CPU中運行,伺服器會緩存線程,所以不需要對每個連接新建或者銷毀一個線程(可以復用緩存中的線程)。
當客戶端連接到MySQL時伺服器需要對其進行認證,如果認證成功,伺服器會繼續驗證該客戶是否有執行某個待定查詢的權限。
2.優化與執行
MySQL會解析查詢,並且創建內部數據結構(解析樹),然後對其進行各種優化,包括重寫查詢SQL、決定表的讀取順序,以及選擇合適的索引等。
對於一個SELECT查詢語句來說:在解析查詢之前,伺服器會先檢查查詢緩存,如果能夠在其中找到對應的查詢,伺服器會直接返回結果,不需要再執行查詢解析、優化和執行整個過程。
二、並發控制
1.讀寫鎖
比如有一張表,多個線程對這張表進行操作,加入剛好有一個線程在對一條數據更改,另一個線程也對其進行讀取操作,那麼進行讀操作的這個線程可能讀到的數據是不正確的,怎麼解決這個問題呢?這時就用到了並發控制,主要是通過兩種鎖來控制的:讀鎖(共享鎖)、寫鎖(排他鎖)
讀鎖是共享的,或者說是相互不阻塞的,即對個線程讀取同一個資源,互不幹擾;寫鎖是排他的,也就是說只要有一個線程對其進行寫操作,那麼其他的讀和寫線程將都會被阻塞。只有這樣才能保證才能保證在給定的時間內只有一個線程在寫操作,並防止其他線程讀取正在寫入的數據。
2.鎖粒度
最理想的情況是:需要寫入哪個對象就鎖定哪個對象。儘量只鎖定需要修改的部分數據,而不是所有的數據。在任何時候,在給定的資源上,鎖定的數據越少,系統的並發程度越高。
但是還有一個問題,加鎖也會消耗資源,鎖的各種操作:獲得鎖、檢查鎖是否已經解除、釋放鎖等,都會增加系統的開銷,如果花費大量的時間來管理鎖,而不是存取數據,那麼系統的性能將會受到影響。
所謂的鎖策略,就是在鎖的開銷和數據的完全性之間尋求平衡。
表鎖是MySQL中最基本的鎖策略,並且是開銷最小的策略(意味著並發程度低),但是表鎖的缺點是在執行插入、刪除、更改的操作時會使其他的用戶線程阻塞。(注意:讀鎖之間是互不影響的)。另外寫鎖比讀鎖的優先級更高。寫鎖可以插到讀鎖中,但是讀鎖卻不能插到寫鎖中。
行級鎖:可以最大程度的支持並發處理(但是同時也帶來了更大的鎖開銷)最典型的就是InnoDB存儲引擎,行級鎖只在存儲引擎層實現。
三、事務
最重要的事務終於到啦,事務即ACID(原子性、一致性、隔離性、持久性),在開始講這四個特性之前我們先舉一個最經典的例子:某帳戶存了1000元,現在用戶A要往裡面存200元、用戶B要往出來取200元。
原子性:一個事務必須被視為不可分割的最小工作單元,整個事務的所有操作要麼全部提交完成,要麼全部失敗回滾,對於一個事務來說不可能執行其中的一部分。那上面例子來說:A要從帳戶取200需要執行以下四步操作:
1 START TRANSACTION;2SELECT'金額'FROM'帳戶表'WHEREuser_id=1221221;3UPDATE'帳戶表'SET'金額'='金額'-200WHEREuser_id=1221221;4COMMIT;
解釋:1.開啟事務 ,2.查詢帳戶有沒有200元 ,3.扣除金額 , 4.提交事務。
原子性就是指這四步完整執行不可再分。
一致性:資料庫從一個一致性的狀態轉換為另一個一致性的狀態。就上面那個例子:如果在第三步執行完系統崩潰,帳戶中的金額還是1000元,因為一個事務沒有執行完,在最終提交前是不會保存到資料庫中的。
隔離性:通常來講一個事務在最終提交前,對其他事務是不可見的。就之前例子來說,第三步執行完,在沒提交之前B帳戶來看到的金額仍然是1000元。是不可見的。
持久性:事務一旦提交其所做的修改就會永遠的被保存到資料庫中,即使系統崩潰也不會丟失。
一個實現了事務的資料庫相比於沒有實現事務的資料庫它需要更強的CPU處理能力、更大的內存、更多的磁碟空間。對於有些不需要事務的查詢類應用選擇一個非事務型的存儲引擎可以獲得更高的性能。
1.隔離級別
一共有四種隔離級別先簡單做個介紹:
A.READ UNCOMMIT(讀未提交)
在這個隔離級別中,事務的修改,即使沒有提交,對其他的事務也是可見的。事務可以讀到未提交的數據,這些數據也被稱為髒讀。
B.READ COMMIT(讀已提交)(不可重複讀)
大多數資料庫系統的默認隔離級別都是讀已提交,但是MySQL不是,MySQL的默認隔離級別是可重複讀。簡單說就是一個事務開始時只能 「看見」 已經提交的事務所做的修改,換句話說,一個事務從開始到提交這個過程中所做的所有修改對其他事務是不可見的。這個級別對於兩次執行相同情況的查詢,可能會得到不同的結果。
C.REPEATABLE READ(可重複讀)
該級別保證了在同一個事務中多次讀取同樣的記錄結果是一致的,但是它無法解決幻讀的問題。
D.SERIALIZABLE(可串行化)
是最高的隔離級別。它通過強制事務串行化執行,避免了所有問題,他會在讀取的每一行記錄上面都加鎖,所以可能導致大量的超時與鎖等待的問題,並發低。
講幾個概念:
1.髒讀:A用戶把錢取出沒有提交,B用戶讀取到修改了的金額為800,過一會A因為異常事務回滾,B再次讀取發現值變為1000,兩次不一樣,第一次讀到的是髒數據。
2.不可以重複讀:B讀到數據為1000後,A修改數據為800並且提交,B再次讀取為800,兩次數據不一致。
3.幻讀:與不可重複讀類似:B讀到一個表裡有10條記錄,A插了一條並提交,B再次讀為11條,感覺發生幻覺一樣。
不同隔離級別引發的問題:
2.死鎖
多個事務在同一資源上相互佔有,並且請求鎖定對方佔用的資源,從而導致惡性循環的現象。
資料庫系統實現了各種死鎖檢測和死鎖超時機制。InnoDB目前處理死鎖的方法是:將持有最少行排它鎖的事務進行回滾。
3.事務日誌
事務日誌可以提高事務的效率,使用事務日誌時:存儲引擎在修改表數據時只需要修改其內存拷貝,再把該修改行為記錄到持久在硬碟上的事務日誌中,不用每次將修改的數據本身持久到硬碟。事務日誌採用追加的方式,寫日誌的操作是磁碟上的一小塊區域內的順序I/O.事務日誌持久後,內存中被修改的數據將在後臺慢慢刷回到磁碟。所以一共需要兩次磁碟I/O:一次寫日誌磁碟I/O,一次刷回磁碟I/O.
4.MySQL中的事務
1.自動提交:MySQL默認採用自動提交的方式。比如每個查詢就是一個事務執行完自動提交。
2.非事務型存儲引擎如:MyISAM無回滾功能。
四、多版本並發控制MVCC
可以認為MVCC是行級鎖的一個變種,它在很多情況下避免了加鎖,MVCC的實現是通過保存數據在某個時間的快照來實現的。
InnoDB的MVCC,是通過在每行記錄後面保存兩個隱藏的列來實現的,這兩個列一個保存了行的創建時間,一個保存了行的刪除時間,存儲的不是真正時間而是系統的版本號。每個新事物開始系統版本號自動遞增。事物開始時刻的版本號作為事物的版本號,用來和查詢到的每行記錄版本號進行比較。
MVCC只在可重複讀和讀已提交兩個隔離級別下工作,其他兩個級別都和MVCC不兼容。因為讀未提交總是讀取最新的數據行,不符合當前事物版本的數據行。可串行化會對所有行加鎖。
我的理解其實MVCC就跟CAS是一個原理,就是一個比較並交換的過程。