Mysql架構與概念

今天開始正式對《高性能Mysql》進行學習,博客主要記錄學習的過程及一些認爲比較重要的知識點,對於一些內容會從Mysql官網進行確認,

一、Mysql的邏輯架構

Mysql在邏輯上主要分爲三部分:

  • 第一部分主要用於處理客戶端連接,授權認證和安全。對於Java程序來說,第一部分主要對應於MySQL Connector/J 
  • 第二部分主要是服務器層,包含Mysql大多數的核心服務功能,例如:查詢解析、分析、優化、緩存以及所有的內置函數,所有跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖。
  • 第三部分主要是存儲引擎:存儲引擎負責Mysql中數據的存儲和提取。服務器通過API與存儲引擎進行通信,這些接口屏蔽了不同存儲引擎之間的差異,使得這些差異對上層的查詢過程透明。

1、連接管理與安全性

每個客戶端連接都會在服務器中擁有一個線程,這個連接的查詢只會在這個單獨的線程中執行,該線程只能輪流在某個CPU核心或者CPU中運行。服務器會負責緩存線程,因此不需要爲每一個新建的連接創建或者銷燬線程。

當客戶端連接到Mysql服務器時,服務器需要對其進行認證。認證基於用戶名、原始主機信息和密碼。一旦連接成功,服務器會繼續驗證該客戶端是否具有執行某個特定查詢的權限。

2、優化與執行

Mysql會解析查詢,並創建內部數據結構(解析樹),然後對其進行各種優化,包括重寫查詢,決定表的讀取順序,以及選擇合適的索引等。用戶可以通過特殊的關鍵字提示(hint)優化器,影響它的決策過程。也可以請求優化器解釋(explain)優化過程的各個因素,使用戶可以知道服務器是如何進行優化決策的,並提供一個參考基準,使用戶重構查詢和schema、修改相關配置,使盡可能的高效運行。

優化器並不關心底層的存儲引擎,但存儲引擎對優化查詢是有影響的。優化器會請求存儲引擎提供容量或某個具體操作的開銷信息,以及表數據的統計信息。

對於SELECT語句,在解析查詢之前,服務器會先檢查查詢緩存(Query Cache),如果能夠找到對應的查詢,服務器就不必再執行查詢解析、優化和執行的整個過程,而是直接返回查詢緩存中的結果集。

二、併發控制

1、讀寫鎖

讀鎖是共享的,或者說是互不阻塞的,寫鎖是排他的,也就是說一個寫鎖會阻塞掐的寫鎖和讀鎖。

2、鎖粒度

一種提高共享資源併發性的方式就是讓鎖定的對象更有選擇性。儘量只鎖定需要修改的部分數據,而不是所有的資源。更理想的方式是,只對修改的數據進行精確的鎖定。任何時候,在給定的資源上,鎖定的數據量越少,則系統的併發程度越高,只要相互之間不發生衝突即可。

問題是加鎖也需要消耗資源,鎖的各種操作,包括獲得鎖,檢查鎖是否已經解除,釋放鎖等,都會增加系統的開銷。如果系統花費大量的時間來管理鎖,而不是存取數據,那麼系統的性能可能因此受到影響。

所謂的鎖策略,就是在鎖的開銷和數據安全性之間尋求平衡。

  • 表鎖:表鎖是Mysql中最基本的鎖策略,並且是開銷最小的策略。表鎖會鎖定整張表。
  • 行級鎖:行級鎖可以最大成都的支持併發處理(同時也帶來了最大的鎖開銷)。行級鎖只在存儲引擎層實現,而Mysql服務器層沒有實現。

三、事務

在Mysql中,事務就是一組原子性的SQL查詢,或者說一個獨立的工作單元。如果數據庫引擎能夠成功的對數據庫應用該組查詢的全部語句,那麼就執行該組查詢。如果其中的任何一條語句因爲崩潰或其他原因無法執行,那麼所有的語句都不會執行。也就是所,事務內的語句,要麼全部執行成功,要麼全部執行失敗。事務要滿足以下四個特性:

  • 原子性(atomicity):一個事務被視爲一個不可分割的最小工作單元,整個事務中的所有操作要麼全部提交成功,要麼全部失敗回滾,對於一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性。
  • 一致性(consistency):數據庫總是從一個一致性的狀態轉換到另外一個一致性的狀態。
  • 隔離性(isolation):通常來說,一個事務所做的修改在最終提交以前,對其他事務是不可見的。
  • 持久性(durability):一旦事務提交,其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,修改的數據也不會丟失。

1、隔離級別:

  • READ UNCOMMITED(未提交讀):在READ UNCOMMITED級別中,事務中的修改,即使沒有提交,對其他事務也都是可見的。事務可以讀取未提交的數據,這也被稱爲髒讀。
  • READ COMMITED(提交讀):READ COMMITED滿足前面提到的隔離性的基本定義:一個事務開始時,只能看見已經提交的事務所做的修改。換句話說,一個事務從開始直到提交之前,所做的任何修改對其他事務都是不可見的。這個級別有時候也叫不可重複讀,因爲兩次執行同樣的查詢可能會得到不一樣的結果。
  • REPETABLE READ(可重複讀):REPETABLE READ解決了髒讀的問題。該級別保證了同一事務中多次讀取同樣記錄的結果是一致的。但理論上,可重複讀隔離級別還無法解決另外一個幻讀的問題。所謂幻讀,是指當某個事務在讀取某個範圍內的記錄時,另外一個事務又在該範圍內插入了新的記錄。
  • SERILIZABLE(可串行化):SERILIZABLE是最高的隔離級別。它通過強制事務串行執行,避免了前面說的幻讀的問題。簡單來說,SERILIZABLE會在讀取的每一行記錄上都加鎖,所以可能導致大量的超時和鎖爭用問題。

2、死鎖

死鎖是指兩個或者多個事務在同一資源上相互佔用,並請求鎖定對方佔用的資源,從而導致惡性循環的現象。當多個事務試圖以不同的順序鎖定資源時,就可能會產生死鎖。多個事務同時鎖定一個資源時,也會產生死鎖。

爲了解決死鎖問題,數據庫系統實現了各種死鎖檢測和死鎖超時機制。Innodb目前處理死鎖的方法是,將持有最少行級排它鎖的事務進行回滾。

3、事務日誌

事務日誌可以幫助提高事務的效率。使用事務日誌,存儲引擎在修改表的數據時只需要修改其內存拷貝再把該修改行爲記錄到持久在硬盤的上的事務日誌中,而不用每次都將修改的數據本身持久到磁盤。事務日誌採用的是追加的方式,因此寫日誌的操作是磁盤上一小塊區域內的順序I/O,而不像隨機I/O需要在磁盤的多個地方移動磁頭,所以採用事務日誌的方式相對來說要快的多。目前大多數存儲引擎都是這樣實現的。我們通常稱之爲預寫式日誌,修改數據需要修改兩次磁盤。

如果數據的修改已經記錄到事務日誌中並持久化,但數據本身還沒有寫回磁盤,此時系統崩潰,存儲引擎在重啓時能夠自動回覆這部分修改的數據。

4、Mysql中的事務(InnoDB)

自動提交(AUTOCOMMIT)

Mysql默認採用自動提交(AUTOCOMMIT)模式。也就是說,如果不顯式的開始一個事務,則每個查詢都被當做一個事務提交操作。

可以通過設置AUTOCOMMIT=0來禁用自動提交模式。

隱式和顯式鎖定

InnoDB採用的是兩階段鎖協議。在事務的執行過程中,隨時都可以執行鎖定,鎖只有在執行COMMIT或者ROLLBACK的時候纔會釋放,並且所有的鎖在同一時刻被釋放,前面描述的鎖定都是隱式鎖定,InnoDB會根絕隔離級別在需要的時候自動加鎖。另外,InnoDB也可以通過特定的語句進行顯式鎖定:

  1. SELECT ... LOCK IN SHARE MODE
  2. SELECT ... FOR UPDATE

四、多版本併發控制(MVCC)

可以認爲MVCC是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。MVCC的實現,是通過保存數據在某個時間點的快照來實現的。也就是說,不管需要執行多長的時間,每個事務看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的數據可能不同。

InnoDB的MVCC是通過在每行記錄後面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的並不是實際的時間值,而是系統版本號。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號,用來和查詢到的每行記錄的版本號進行對比。下面看一下REPETABLE READ隔離級別下,MVCC具體是如何操作的。

SELECT

InnoDB會根據以下兩個條件檢索每行記錄:

  1. InnoDB只查找版本號早於當前事務版本號的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要麼是在事務開始之前已經存在的,要麼是事務自身插入或者修改過的。
  2. 行的刪除版本要麼未定義,要麼大於當前事務的版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。

只有符合上述兩個條件的記錄,才能返回作爲查詢結果。

INSET

InnoDB爲插入的每一行保存當前西榮版本號作爲行版本號

DELETE

InnoDB爲刪除的每一行保存當前系統版本號作爲行刪除標識。

UPDATE

InnoDB爲插入一行新紀錄,保存當前系統版本號作爲行版本號,同樣保存當前系統版本號到原來行作爲行刪除標識。

MVCC只在REPETABLE READ和READ COMMITED這兩個隔離級別下工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章