高性能MySQL&&MySQL架構

注:本篇是《高性能MySQL》第三版的讀書筆記。基於MySQL5.5

 

MySQL的架構與歷史

如下爲MySQL的邏輯架構圖

最上層是正常的連接處理、授權認證、安全等。

中間是核心的服務。查詢解析、分析、優化、緩存預計所有內部函數,所有跨越存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖。

第三層包含了存儲引擎,存儲引擎負責數據的存儲和提取。

MySQL服務器通過API與存儲引擎通信,來做到屏蔽存儲引擎之間的差異。

連接管理與安全

每個客戶端打進來都會在服務器中擁有一個線程池的線程,這個連接的查詢只會在這個單獨的線程中進行。線程在CPU和核心中輪流獲取資源,服務器維護了一個連接池(線程池),保證不會爲每個連接都創建一個新的線程。

當客戶端連接到MySQL服務器時,首先進行認證,並查看是否使用了SSL的方式(用X.509證書認證)、認證過了查詢客戶端對某個查詢是否有相應的權限。 沒有權限需要對這個登錄的用戶授權。grant

mysql  -uroot  -p123456  -h127.0.0.1   

優化與執行

Mysql會解析查詢,並創建內部數據結構(解析樹),然後對其進行各種優化,包括重寫查詢,決定表的讀取順序,選擇索引等。

併發控制

MySQL在兩個層面進行併發控制,服務器層和存儲引擎層。

想到併發,第一想的肯定是鎖,那麼鎖,首先想到的肯定是類似Java的synchronized  一個一個來。但是這是數據庫這麼玩就涼了。所以讀寫鎖也就成爲一個好的解決辦法了。

讀寫鎖分爲讀鎖和寫鎖。即共享鎖和排他鎖。共享鎖就是多個用戶可以訪問同一個資源。排他鎖是隻要這行數據拿到排它鎖,其他對這行數據的讀寫操作都是被阻塞的、這樣確保在給定時間,只有一個用戶能寫入,並且其他用戶讀也不會出錯。

顆粒度是提高併發的一種選擇。

表鎖:基本的鎖,類似上面的讀寫鎖加在表上,讀互相不影響,寫就把表鎖住了。誰也讀不了。

行鎖:最大程度支持併發,類似上面讀寫鎖加在一行數據。寫這行數據會導致其他人讀不了這行數據,別的能讀。鎖開銷大。

 

事務

事務就是一組SQL語句,如果數據庫引擎能成功都執行就成功,有執行失敗的就全部都失敗。

關係型數據庫事務的ACID

example:

查賬號是否有200塊 -----   當前賬號減200  ---- 兒子賬號多200

select   balance   from  checking  where  uid = 1000

update  checking  set  balance = balance - 200 where  uid = 1000

update  savings  set  balance  =  balance  +200  where uid = 1000

1.原子性:一個事務要麼都執行,要麼都失敗。

2.一致性:數據庫總是從一個一致性狀態轉換到另外一個一致性狀態。這兩個一致性可以理解爲確定的、中間出問題就不行了

3.隔離性:多個事務之間,如果第一個事務得到的balance是 500   此時另一個事務把balance改成了400並持久化到數據庫了。那麼再執行 balance - 200 set 的結果就是300 了。這不合適、應該本次事務失敗,在重新獲取balance = 400  然後再減。

4.持久性:一旦事務提交,其所做的修改就被持久化到數據庫中了。

四種隔離級別

1.讀未提交:事務中的修改即使沒提交,其他事務也是可以看到的。其他事務可以讀取沒有被提交的數據,也叫髒讀。

2.提交讀:事務開始時只能看見已經提交的事務所做的修改。如果在這個事務進行時,其他事務提交他是不知道的。如果事務回滾再次讀到的數據就不一樣了也叫不可重複讀。

3.可重複讀:當一個事務在讀取某個範圍內的記錄時,其他事務往這個範圍內又插入了數據,之前的事務再讀,會產生幻行,也叫做幻讀。(MySQL默認隔離級別)行級鎖

4.可串行化:強制事務串行執行,會在讀取每一行數據的時候加鎖。表級鎖

事務的隔離級別可以通過 set session transation isolation level read committed; 來改。

死鎖:多個事務在同一個資源上互相佔用。

A  

transation

update  price_table set price = price -10 where uid = 10

update  price_table set price = price -10 where uid = 11

commit

B

transation

update  price_table set a= a-10 where uid = 11
update  price_table set a= a-10 where uid = 10

commit

當A事務執行第一個update時B事務也在執行第一個update  AB對對應的行數據上了鎖,那麼AB都在等待對方釋放鎖才能繼續修改第二條語句,此時就是死鎖了。

innodb目前將持有最少行級排它鎖的事務進行回滾。有些死鎖也是由於存儲引擎的實現方式導致的。

事務日誌

事務日誌可以提高事務的效率。事務日誌存儲操作記錄,比如insert一個數據,存儲引擎只需要修改數據的內存拷貝,並將操作存到事務日誌中,而不是直接將數據持久化到磁盤。跟elasticsearch的translog一個套路。事務日誌是順序寫入的,不會導致磁盤的隨機IO。即使我們機器宕掉了,再啓動也會根據translog恢復數據。

對於Mysql常見的存儲引擎,innodb和myisam中,innodb是支持事務顯示創建commit和rollback的。而myisam不存在commit和rollback的操作。事務都是自動提交的。 對於一些alter對錶的操作,會commit之前SQL並開始使用新的事務操作。

innodb會根據隔離級別在需要的時候自動加鎖。事務是屬於存儲引擎層的。不屬於服務器層。不同存儲引擎的事務不一樣。

 

多版本併發控制(MVCC)

MySQL大多數事務型存儲引擎都不是簡單的行級鎖,基於對於併發場景性能的提升,一般都實現了多版本併發控制。

MVCC可以理解爲行級鎖的變種,性能更高了。典型的有樂觀併發控制和悲觀併發控制。

InnoDB的MVCC是通過在每行記錄後面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建版本號,一個保存了過期系統版本號。每開啓一個事務,系統版本號會遞增,事務開始時刻的系統版本號會作爲事務的版本號,用來和查詢的記錄對比。

下面是可重複讀隔離級別的MVCC操作。

select   滿足1.版本早於或等於當前事務版本號的行。2.行的刪除版本要麼未定義要麼大於當前事務版本號。

insert   插入的行用當前系統版本號作爲行版本號,刪除版本號爲空。

delete  刪除的行用當前系統版本號作爲刪除版本號。

update   innodb的實現是插入了一條新記錄,用當前版本號作爲行版本號,當前版本號也作爲之前記錄的刪除版本號。

可以看到跟elasticsearch又是一個玩法。所以更新是比想像的更麻煩的。

MVCC只在可重複讀和讀已提交兩個隔離級別下工作。

 

Mysql將每個數據庫報錯爲數據目錄下的一個子目錄。創建表時,MySQL會在數據庫子目錄下創建一個和表同名的.frm文件保存表的定義。不同存儲引擎保存數據和索引的方式是不同的。

可以使用 show table status like 'user'    來查詢某個表的相關信息。

 

InnoDB存儲引擎

InnoDB是基於聚簇索引建立的,聚簇索引對主鍵查詢有很高的性能,非主鍵索引中包含主鍵列,所以主鍵太大會導致索引文件特別大,因此主鍵應該儘可能少。有行級鎖,5.6版本之前不支持全文索引。之後支持了(不理想)。

MyISAM存儲引擎

不支持事務和行級鎖。崩潰後無法恢復。加鎖的維度是整張表。myisam存儲引擎會對錶進行壓縮。如果發現所有查詢屬於Locked狀態,就很有可能是表鎖導致的。

InnoDB有事務,備份,崩潰恢復等特性。使用MySQL基本就選它沒錯了。

MyISAM的壓縮使得數據傳輸比較快。但是一些缺點導致InnoDB的優先於它。

 

不建議中途修改數據的存儲引擎,可能會導致一些意想不到的問題。後文會詳細描述存儲引擎。

 

 

 

 

 

 

 

 

 

 

 

 

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