高性能mysql 讀書筆記 MySQL架構

1.MySQL邏輯架構

在這裏插入圖片描述

  1. 第一層所說的客戶端應該就是mysql workbench。負責連接處理,授權認證,安全等。
  2. 第二層架構是MySQL的核心,核心的服務功能都在這一層。包括查詢解析,分析,優化,緩存以及所有的內置函數(例如,日期,時間,數學和加密函數),所有誇存儲引擎的功能都在這一層實現:存儲功能,觸發器,視圖等。
  3. 第三層包含了存儲引擎,存儲引擎負責MySQL中數據的存儲和提取。和GNU/Linux下的各種文件系統一樣,每個存儲引擎都有它的優勢和劣勢。服務器通過API與存儲引擎進行通信。這些接口屏蔽不同存儲引擎之間的差異,是的這些差異堆上層的查詢透明。

2.併發控制

2.1讀寫鎖

併發控制方式多是採用鎖機制。
通常是共享鎖(讀鎖)排他鎖(寫鎖)
讀鎖是共享的,多個客戶在同一個時刻可以同時讀取同一個資源,互不干擾。加了讀鎖後可以再加讀鎖,但不可加寫鎖。
寫鎖是排他的,也就是說在寫的同時不允許其他的寫鎖來寫和讀鎖來讀。這樣就能防止髒數據的進入。

2.2鎖粒度

鎖需要消耗資源,鎖的對象過大也影響併發性,鎖過多也會消耗過多資源,所以鎖粒度的大小會影響性能。所以鎖策略就格外重要。MySQL提供了多種鎖策略,下面介紹最重要的兩個鎖策略。

2.2.1表鎖

表鎖是Mysql中開銷最小的鎖。它的策略是會鎖定一張表,如果用戶對錶寫入(插入,更新,刪除),就會將表鎖住,同時阻塞其他的用戶對這張表的讀和寫。在某些場景下,寫鎖比讀鎖更高的優先級。寫鎖請求會插入到讀鎖隊列的前面,反之,讀鎖不能插入到寫鎖前面。

2.2.2 行級鎖

行級鎖可以最大成都地支持併發處理(同時帶來了最大的鎖開銷)。行鎖只在存儲引擎層實現。

3.MySQL事務

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

3.1事務的ACID

原子性(atomicity):一個事務必須被視爲不可分隔的最小工作單元,整個事務中的所有操作要麼全部提交成功要麼全部失敗回滾,對於一個事務來說,不可能只執行其中的一部分操作。

一致性(consisitency):數據庫總是從一個一致性的狀態轉換到另一個一致性的狀態。

隔離性(isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。

持久性(durabilty):一旦事務提交,則其所做的修改就會永久保存到數據庫中。

3.2 隔離級別

3.2.1 不使用隔離級別可能存在的問題

髒讀:一個事務讀了另一個事務修改了但未提交的數據。
不可重複讀:在一個事務中多次讀取同一個數據,但讀取的數據不同。可能是被修改了或被刪除了。
幻讀:在一個事務中多次讀取同一個數據集合,但讀取的數據集合不同。可能是插入了新的數據。

3.2.2 隔離級別

每種存儲引擎實現的隔離級別不盡相同。
READ UNCOMMITTED(未提交讀)
在次級別中,事務中的修改即使沒有提交在其他事務中也是可見的。其他事務可以讀取未提交的數據。

READ COMMITTED(提交讀)
只能讀取已提交的事務所做的修改。
能解決髒讀。
大多數數據庫系統的默認隔離級別都是READ COMMITTED,但MySQL不是。

REPEATABLE READ(可重複讀)
該級別保證在同一個事務中多次讀取同樣記錄的結果是一致的。
解決了髒讀和不可重複讀。
可重複讀是MySQL的默認事務隔離級別。

SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔離級別。它強制事務串行執行,也就是一個一個執行。簡單來說,SERIALIZABLE會在讀取的每一行數據上都加鎖,所以可能導致大量的超時和鎖競爭。
解決了髒讀,不可重複讀和幻讀。但效率低。

3.3 死鎖

死鎖是指兩個或者多個事務在同一資源上相互佔用,並請求鎖定對方佔用的資源,從而導致惡性循環的現象。

比如,事務A佔用了資源1,事務B佔用了資源2。同時地,事務A請求資源2,但事務B鎖定了資源2,事務B請求資源1,但事務A鎖定了資源1。於是就產生了死鎖。

3.3.1 產生死鎖的必要條件(插入一下操作系統的知識)

1.互斥條件:併發進程(在數據庫中就是事務)鎖要求和佔有的資源是不能同時被兩個以上進程使用或操作的,進程對它所需要的資源進行排他性控制。
2.不剝奪條件:進程所獲得的資源在未使用完畢之前,不能被其他進程強行剝奪,而只能有獲得該資源的進程自己釋放。
3.部分分配。進程每次申請它所需要的一部分資源,在等待新資源的同時,繼續佔用已分配到的資源。(意思就是資源不同時分配,是有先後順序的,正因爲有先後才能導致死鎖。)
4.環路條件:存在一種進程循環鏈,鏈中每一個進程已獲得的資源同時被下一個進程所請求。

只要使上述4個必要條件中的某一個不滿足,死鎖就可以消除。

3.4 事務日誌

事務日誌可以幫助提高事務的效率。使用事務日誌,存儲引擎在修改表的數據時只需要修改其內存拷貝,再吧該修改行爲記錄到持久在硬盤上的事務日誌中,而不用每次都將修改的數據本身持久到磁盤中。這有什麼區別呢?事務日誌採用的是追加的方式,使用寫日誌的操作是磁盤上一下快區域內的順序I/O,而不想每次修改數據的隨機I/O。隨機I/O需要磁盤的磁頭在多個地方移動,效率很低,使用事務日誌能提高效率。事務日誌持久以後,內存中被修改的數據在後臺可以慢慢地刷回到磁盤。我們通常稱之爲預寫式日誌。

3.4.1 redo和undo日誌的區別(這也是我自己插入的)

undo是指數據庫爲了保持讀一致性,存儲歷史數據在一個位置。undo日誌用於存放數據修改被修改前的值,如果這個修改出現異常,可以使用undo日誌來實現回滾操作,保證事務的一致性。
​ 當數據庫對數據做修改的時候,需要把數據頁從磁盤讀到buffer pool中,然後在buffer pool中進行修改,那麼這個時候buffer pool中的數據頁就與磁盤上的數據頁內容不一致,稱buffer pool的數據頁爲dirty page 髒數據,如果這個時候發生非正常的DB服務重啓,那麼這些數據還沒在內存,並沒有同步到磁盤文件中(注意,同步到磁盤文件是個隨機IO),也就是會發生數據丟失,如果這個時候,能夠在有一個文件,當buffer pool 中的data page變更結束後,把相應修改記錄記錄到這個文件(注意,記錄日誌是順序IO),那麼當DB服務發生crash的情況,恢復DB的時候,也可以根據這個文件的記錄內容,重新應用到磁盤文件,數據保持一致。

3.5 MySQL中的事務

MySQL提供了兩種事務的存儲引擎:InnoDB和NDB Cluster。另外還有一些第三方存儲引擎也支持事務,比較知名的包括XtraDB和PBXT。

3.5.1 自動提交

MySQL默認採用自動提交(autocommit)模式。也就是說不是顯式的開始一個事務,則每個查詢都被當作一個事務執行提交操作。在當前連接中,可以通過設置autocommit變量來棄用或禁用自動提交模式:
在這裏插入圖片描述
1或者ON表示啓用,0或者OFF表示禁用。當autocommit=0時,所有的查詢都是在一個事務中,直到顯式地執行COMMIT提交或者ROLLBACK回滾,該事務結束,同時又開始新事務。

**修改autocommit對非事務型的表,比如MyISAM或者內存表,不會有任何影響。**堆這類表來說,沒有COMMIT或者ROLLBACK的概念(因爲根本就沒事務),也可以說是相當於一直處於autocommit啓用的模式。

有一些命令在執行之前會強制執行COMMIT提交當前的活動事務。 比如在數據定義語言(DDL)中,如果是會導致大量數據改變的操作,比如ALTER TABLE。

MySQL可以通過執行SET TRANSACTION ISOLATION LEVEL 命令來設置隔離級別。新的隔離級別會在下一個事務開始的時候生效。可以在配置文件中設置整個數據庫的隔離級別,也可以值改變當前會話的隔離級別:
在這裏插入圖片描述

3.5.2 在事務中混合使用存儲引擎

MySQL服務器層(架構的第二層)不管理事務,事務是有存儲引擎(第三層)實現的。所以在同一個事務中,使用多種存儲引擎是不可靠的:

  • 如果在事務中混合使用了事務型和非事務型的表(例如InnoDB和MyISAM表),在正常提交的情況下不會有什麼問題
  • 但如果該事務需要回滾,非事務型的表上的變更就無法撤銷,這會導致數據庫處於不一致的狀態,這種情況就很難修復,事務的最終結果將無法確定。所以,爲每張表選擇合適的存儲引擎非常重要。
  • 在非事務型的表上指向事務相關操作的時候,MySQL通常不會發出提醒,也不會報錯。有時候只有回滾的時候纔會發出一個警告:“某些非事務型的表上的變更不能被回滾”。但大多數情況下,對非事務型表的操作都不會有提示。

3.5.3 隱式和顯式鎖定

InnoDB採用的是兩階段鎖協議。在事務執行過程時都是可以執行鎖定的,鎖只有在執行COMMIT或者ROLLBACK的時候纔會釋放,並且所有的鎖是在同一時刻被釋放。前面所描述的鎖定都是隱式鎖定,InnoDB會根據隔離級別在需要的時候自動枷鎖。

InnoDB支持通過特定的語句進行顯式加鎖,不過這些語句不屬於SQL規範:
在這裏插入圖片描述

4.多版本併發控制(MVCC)

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提升併發性能的考慮,他們一般都同時實現了多版本併發控制(MVCC)。

可以認爲MVCC是航機所的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的行。

MVCC的實現:通過保存數據在某個時間的快照(可以理解爲存儲了時間戳和當時的數據)實現。
因爲有了時間戳,事務就可以用事務開始的時間去讀取快照,不同的開始時間可能讀取不同的數據。(這也就解決了幻讀)。

樂觀鎖和悲觀鎖

不同存儲引擎的MVCC實現是不同的,有樂觀鎖和悲觀鎖。

樂觀鎖(Optimistic Lock)
顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。

悲觀鎖(Pessimistic Lock)
顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。

InnoDB的MVCC實現

InnoDB的MVCC是通過在每行記錄後保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的並不是實際的時間值,而是系統版本號(越晚產生的版本號,數值越大,所以你就可以理解爲時間值)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作爲事務的版本號,用來查詢到的每行記錄的版本號比較。

使用這兩個版本號使得大多數讀操作都可以不用加鎖。

MVCC只在REPEATABLE READ 和READ COMMITTED兩個隔離級別下工作。READ UNCOMMITTED總是讀取最新的數據行。SERIALIZABLE則會堆所有讀取的行都加鎖。

REPEATABLE READ 隔離模式下,MVCC具體操作:

(1)select
InnoDB會根據一下兩個條件檢查每行記錄

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

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

(2)insert
InnoDB爲新插入的每一行保存當前系統版本號作爲行版本號。

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

(4)update
InnoDB爲插入一行新記錄,保存當前系統版本號作爲行版本號,同時保存當前系統版本號爲原來的行作爲行刪除標識。

5.MySQL的存儲引擎

這個小結概要描述MySQL的存儲引擎,不會設計太多細節。之後會再寫一篇文章總結。

5.1 InnoDB存儲引擎

InnoDB是MySQL的默認事務型引擎使用最廣泛的存儲引擎,一般優先使用InnoDB存儲引擎,它被設計用來處理大量的短期事務,短期事務大部分情況是正常提交的,很少會回滾。

1.數據存儲形式
InnoDB的數據存儲在表空間中,表空間是由InnoDB管理的一個黑盒子,由一系列的數據文件組成。使用InnoDB時,會將數據表分爲.frm和idb兩個文件進行存儲。.frm存儲表結構,.ibd存儲表的數據和索引。

2.鎖的粒度
InnoDB採用MVCC來支持高併發,並且實現了四個標準的隔離級別。其默認級別是REPEATABLE READ,並通過間隙鎖策略防止幻讀的出現。間隙鎖是的InnoDB不僅僅鎖定查詢設計的行,還會堆索引中的間隙進行鎖定,防止幻影行的插入。

3.事務
InnoDB是典型的事務型存儲引擎。

4.數據的存儲特點
InnoDB表是基於聚簇索引建立的。聚簇索引對主鍵查詢有很高的性能。不過它的二級索引中必須包含主鍵列,索引如果主鍵列很大的話,其他的所有索引都會很大。

5.2 MyISAM存儲引擎

1.數據存儲形式
MyISAM採用的是索引與數據分離的形式,將數據保存在三個文件中.frm.MYD,.MYIs。.frm存儲表結構,.MYD存儲表的數據,.MYI存儲表索引。

2.鎖的粒度
MyISAM不支持行鎖,所以讀取時對錶加上共享鎖,在寫入是對錶加上排他鎖。由於是對整張表加鎖,相比InnoDB,在併發寫入時效率很低。

3.事務
MyISAM不支持事務。

4.數據的存儲特點
MyISAM是基於非聚簇索引進行存儲的。

5.其他
MyISAM提供了大量的特性,包括全文索引,壓縮,空間函數,延遲更新索引鍵等。

進行壓縮後的表是不能進行修改的,但是壓縮表可以極大減少磁盤佔用空間,因此也可以減少磁盤IO,從而提供查詢性能。

全文索引,是一種基於分詞創建的索引,可以支持複雜的查詢。

延遲更新索引鍵,不會將更新的索引數據立即寫入到磁盤,而是會寫到內存中的緩衝區中,只有在清除緩衝區時候纔會將對應的索引寫入磁盤,這種方式大大提升了寫入性能。

5.3 InnoDB與MyISAM的對比與選擇

兩種存儲引擎各有各的有點,MyISAM專注性能,InnoDB專注事務。兩者最大的區別就是InnoDB支持事務,和行鎖。
在這裏插入圖片描述
如何在兩種存儲引擎中進行選擇?

① 是否有事務操作?有,InnoDB。

②是否存儲併發修改?有,InnoDB。

③是否追求快速查詢,且數據修改較少?是,MyISAM。

④是否使用全文索引?如果不引用第三方框架,可以選擇MyISAM,但是可以選用第三方框架和InnDB效率會更高。

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