Mysql是主流的開源關係型數據庫,提供高性能的數據存儲服務。咱們在作後端開發時,性能瓶頸每每不是應用自己,而是數據庫層面。因此掌握Mysql的一些底層原理有助於咱們更好地理解Mysql,對Mysql進行性能調優,從而開發高性能的後端服務。sql
Mysql的邏輯架構以下圖:數據庫
最上層是處理客戶端過來的鏈接的。主要作鏈接處理、受權認證、安全等。Mysql在這一層維護了一個線程池,用於處理來自客戶端的鏈接。Mysql可使用用戶名密碼認證,也可使用SSL基於X.509證書認證。後端
第二層由三部分組成:查詢緩存、解析器、優化器。解析器用來解析SQL語句,優化器會對解析以後的語句進行優化。在解析查詢前,服務器會先檢查查詢緩存,若是能在其中找到對應的查詢結果,則無需再進行查詢解析、優化等過程,直接返回查詢結果。存儲過程、觸發器、視圖等都在這一層實現。緩存
第三層是存儲引擎,存儲引擎負責在MySQL中存儲數據、提取數據、開啓一個事務等等。存儲引擎經過API與上層進行通訊,這些API屏蔽了不一樣存儲引擎之間的差別,使得這些差別對上層查詢過程透明。存儲引擎不會去解析SQL。安全
Mysql最經常使用的存儲引擎是InnoDB服務器
若是多個線程同時操做數據,就有可能引起併發控制的問題。本文接下來將介紹Mysql是如何控制併發讀寫的。架構
若是多個線程都只是讀數據,其實能夠一塊兒讀,不會互相影響,這個時候應該使用「讀鎖」,也稱爲共享鎖。獲取讀鎖的線程之間互相不會阻塞,能夠同時讀取一個資源。併發
若是有一個線程須要寫數據,則應該使用「寫鎖」,也成爲排它鎖。寫鎖會阻塞其它的寫鎖和讀鎖,直至寫操做完成。性能
首先明確一個概念:在給定的資源上,須要加鎖的數據越少,系統可以承載的併發量就越高。但加鎖也是須要消耗資源的,若是系統花費大量的時間來管理鎖,而不是存取數據,那麼系統的性能可能會所以受影響。優化
因此一個好的「鎖策略」就是要在鎖的開銷和數據的安全性之間尋求平衡,Mysql支持多個存儲引擎的架構,每種存儲引擎均可以實現本身的鎖策略和鎖粒度。
表鎖顧名思義就是鎖住整張表。表鎖開銷比較小。對錶加寫鎖後,其它用戶對這張表的全部讀寫操做都會被阻塞。在Mysql中,儘管存儲引擎能夠提供本身的鎖,但Mysql有時候也會使用表鎖,好比ALTER TABLE
之類的語句。
寫鎖比讀鎖有更高的優先級,所以一個寫鎖請求可能會被插入到讀鎖隊列的前面。
行級鎖即鎖住整行,能夠最大程度地支持併發處理,但加解鎖的開銷也會比較大。行級鎖只在儲存引擎層實現,全部的存儲引擎都以本身的方式實現了行級鎖。
MVCC即「多版本併發控制」,能夠認爲MVCC是行級鎖的一個變種,可是它在不少狀況下避免了加鎖操做,所以開銷更低。
主流的關係型數據庫都實現了MVCC,但實現機制各有不一樣。實際上MVCC也沒有一個統一的標準。但大都實現了非阻塞的讀操做,寫操做也只是鎖定必要的行。
MVCC保證的是每一個事務裏面在執行期間看到的數據都是一致的。但不一樣的事務因爲開始的時間不一樣,因此可能對同一張表,同一時刻看到的數據是不同的。
在Mysql的InnoDB引擎,是經過給每行記錄後面保存兩個隱藏的列來實現的。一個是保存行的建立時間,另外一個保存了行的過時時間(或刪除時間)。
實際上存儲的並非實際的一個時間戳,而是「系統版本號」。
每次開啓一個事務,系統版本號都會遞增。事務開始時,系統版本號會做爲事務的版本號,用來和查詢到的行的版本號進行比較。下面分別介紹常見的CRUD操做中版本號是怎麼工做的:
INSERT
保存當前系統版本號做爲行版本號
DELETE
保存當前的系統版本號到這行數據的「刪除版本」。
UPDATE
插入一行新紀錄,保存當前系統版本號做爲行版本號,同時保存當前系統版本號到原來的行的「刪除版本」。
SELECT
MVCC只在REPEATABLE READ和READ COMMITTED兩個隔離級別下工做,其它兩個隔離級別不能工做。由於READ UNCOMMITTED老是讀取最新的數據防,而不是符合當前事務版本的數據行。而SERIALIZABLE則會對全部讀取的行都加鎖。