MySQL架構
[TOC]mysql
1. 邏輯架構
MySQL邏輯架構圖
第一層爲客戶端的鏈接認證,C/S都有此架構
第二層爲服務器層,包含MySQL的大多數核心服務功能
第三層包含了存儲引擎,服務器經過API與其通訊,API規避了不一樣存儲引擎的差別,不一樣存儲引擎也不會互相通訊,另外存儲引擎不會去解析SQL(InnoDB是例外,它會解析外鍵定義,由於服務器自己沒有實現該功能)
1.1 鏈接管理及安全性
1.2 優化和執行
MySQL會解析查詢,建立內部數據結構(解析樹),並對其進行各類優化(重寫查詢、決定表的讀取順序、選擇適合的索引)
用戶能夠經過特殊的關鍵字提示(hint)優化器,影響MySQL的決策過程。也能夠請求優化器解釋(explain)優化過程的各個因素,便於用戶重構查詢和schema,修改相關配置
優化器不關心表使用的存儲引擎,可是存儲引擎對優化查詢有影響。優化器會請求存儲引擎提供容量或某個具體操做的開銷信息,已經表數據的統計信息等。
對於SELECT語句,在解析查詢前,服務器會先檢查查詢緩存(Query Cache)。
2. 併發控制
兩個層面的併發控制: 服務器層和存儲引擎層數據庫
2.1 讀寫鎖
共享鎖(shared lock), 讀鎖(read lock):共享,相互不阻塞
排他鎖(exclusive lock), 寫鎖(write lock):排他(會阻塞其它的讀寫鎖)
2.2 鎖粒度
一種提供共享資源的併發性:讓鎖定對象更有選擇性。儘可能只鎖定須要修改的部分數據\數據片,鎖定的數據量越少,併發程度越高。
鎖的各類操做(得到鎖,檢查鎖是否解除,釋放鎖)須要消耗資源。
鎖策略:
表鎖(table lock):
最基本、開銷最小的策略。服務器層實現
鎖定整張表。寫鎖阻塞其它鎖,讀鎖互不阻塞。
特定場景下,表鎖也可能有良好的性能。如READ LOCAL表鎖支持某些類型的併發寫操做。寫鎖比讀鎖有更高優先級,可能會被插入到讀鎖隊列的前面。
存儲引擎能夠管理本身的鎖,服務器層仍是會使用各類有效的表鎖去實現不一樣的目的。如,服務器會爲ALTER TABLE等語句使用表鎖,而忽略存儲引擎的鎖機制。
行級鎖(row lock):
最大程度地支持併發處理,也帶來了最大的鎖開銷。
只在存儲引擎實現(InnnoDB和XtraDB等)
3. 事務
事務是一組原子性的SQL查詢,或者說一個獨立的工做單元。
事務的ACID:
原子性(atomicty):一個不可分割的最小工做單元。
一致性(consistency):數據庫老是從一個一致性狀態轉換到另外一個一致性的狀態。
隔離性(isolation):一個事務所作的修改在最終提交之前,對其餘事務是不可見的。
持久性(durability):事務提交後,其所作的修改會永久保存到數據庫中。(沒有100%的持久性持久性保證策略)
3.1 隔離線的隔離級別
SQL標準中的四種隔離級別:緩存
READ UNCOMMITED(未提交讀):
事務中的修改,即便沒有提交,對其它事務也是可見的。
事務讀取未提交的數據,稱爲髒讀(Dirty READ)。
性能並不比其它級別好太多,但確少了不少好處,不推薦。
READ COMMITED(提交讀)、不可重複讀(nonrepeatable read):
大多數數據庫的默認級別,但MySQL不是。
一個事務只能讀取已提交的事務所作的修改,換句話說,一個事務從開始直到提交以前,所作的任何修改對其它事務都是不可見的。
可能會致使虛讀,如事務A兩次讀取數據,事務B在這之間修改了數據,這兩次讀取會有不同的結果,便可讀取其它事務的增刪改
REPEATABLE READ(可重複讀):
MySQL默認級別。
解決髒讀問題,保證在同一個事務中屢次讀取一樣記錄的結果是一致的。
可能會致使幻讀(Phantom Read),事務A讀取並修改數據,事務B也在該範圍修改了數據(插入或刪除),事務A再次讀取該範圍的數據,發現了幻行(Phantom Row),便可讀取其它事務的增刪
SERIALIZABLE(可串行化):
最高級別的隔離級別,強制事務串行執行。
在讀取的每一行數據上都加鎖,致使大量的超時和鎖爭用問題。
隔離級別
髒讀可能性
不可重複讀可能性
幻讀可能性
加鎖讀
未提交讀
Yes
Yes
Yes
No
提交讀
No
Yes
Yes
No
可重複讀
No
No
Yes
No
可串行化
No
No
No
Yes
3.2 死鎖
死鎖是指兩個或多個事務在同一個資源上相互佔用,並請求鎖定對方佔用的資源,從而致使惡性循環的現象。
產生緣由:
解決方案(部分或徹底回滾其中一個事務):
死鎖檢測。InnoDB處理死鎖的方法:將持有最少行級的排它鎖的事務進行回滾(比較簡單的回滾算法)
死鎖超時機制,超時後放棄對鎖的請求
3.3 事務日誌(預寫式日誌,Write-Ahead Logging)
使用事務日誌,存儲引擎修改表數據,只需修改其內存拷貝,再將該行爲記錄到持久在硬盤的事務日誌中。
大多數存儲引擎的實現方案,修改數據需寫兩次磁盤(第一次爲日誌記錄,第二次爲數據)
優勢:
提升事務的效率
速度快。採用追加方式,寫日誌的操做是磁盤一小塊區域的順序IO,而不是多區域的隨機IO。
3.4 MySQL中的事務
事務型的存儲引擎:MySQL的如InnoDB和NDB Cluster,第三方的如XtraDB和PBXT。安全
自動提交(AUTOCOMMIT):服務器
MySQL的默認模式。如不顯示地開始一個事務,每一個查詢都被看成一個事務執行提交操做。數據結構
在當前鏈接能夠經過設置AUTOCOMMIT變量來啓用或禁用自動提交模式。當禁用時,全部的查詢都是在一個事務中,直到顯式地執行COMMIT或ROLLBACK,該事務結束後又開始另外一個新的事務。架構
mysql> SHOW VARIABLES LIKE 'AUTOCOMMIT'; mysql> SET AUTOCOMMIT = 1;複製代碼
對非事務型地表,如MyISAM或者內存表,不會有任何影響。由於這類表沒有COMMIT或ROLLBACK的概念,也就是說一直處於AUTOCOMMIT模式。併發
在數據定義語言(DDL)中,如ALTER TABLE、LOCK TABLES等致使大量數據改變的操做,會在執行以前強制COMMIT提交當前事務。
SQL類型
MySQL能夠在當前會話設置隔離級別,新的隔離級別會在下一個事務開始的過後生效。
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITED;複製代碼
MySQL可以識別全部的4個ANSI隔離級別,InnoDB引擎支持全部的隔離級別。
在事務中混合使用存儲引擎
MySQL服務器層無論理事務,事務是由下層的存儲引擎實現的。因此在同一個事務,使用多種存儲引擎不可靠。
如在事務中混合使用存儲引擎,如InnoDB和MyISAM,正常狀況下不會有問題,但須要回滾時,非事務型的表上的變動沒法撤銷,致使數據庫處於不一致的狀態,並且MySQL對非事務型的表操做不會有提示。
總結:最好不要在一個事務中混合使用存儲引擎
隱式和顯式鎖定
隱式鎖定:
InnoDB採用兩階段鎖定協議(two-phase locking protocol)。事務執行過程當中,隨時均可以執行鎖定,鎖只在COMMIT或ROLLBACK時被釋放,而且全部的鎖都在同一時間釋放。InnoDB會根據隔離級別在須要的時候自動加鎖。
顯式鎖定:
其它鎖定
MySQL支持LOCK TABLES和UNLOCK TABLES語句,這是在服務器層實現的,和存儲引擎無關。並不能代替事務處理。在InnoDB使用,會嚴重影響性能,效果沒有它的行級鎖好
建議:除了事務中禁用AUTOCOMMIT,可使用LOCK TABLES以外,其他任何使用都不要顯式地執行,無論使用地是什麼存儲引擎。
4. 多版本併發控制(MVVC)
MySQL的大多數存儲引擎,Oracle以及PostgreSQL都實現MVVC,但實現的機制不盡相同,典型的有樂觀併發控制和悲觀併發控制。
目的:
鄙棄簡單地行級鎖,可視爲行級鎖的變種,提高併發性能。
在不少狀況下避免了加鎖操做,開銷更低。
實現了非阻塞的讀操做,寫操做也只鎖定必要的行
實現原理:
保存數據在某個時間點的快照來實現。
無論執行多長時間,每個事務看到的數據都是一致的。
根據事務開始時間的不一樣,每個事務對同一張表,同一個時刻看到的數據多是不同的。
InnoDB簡化版的MVVC工做原理:
經過在每行記錄後面保存兩個隱藏的列,一列保存了行的建立時間,一個保存行的過時時間。存儲的並非實際的時間值,而是系統版本號。每個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會做爲事務的版本號,用來和查詢到的每行記錄的版本號進行比較。
只在REPEATABLE READ和READ COMMITED兩個隔離級別下工做。
優勢:大多數讀操做不用加鎖,讀操做簡單,性能很好,也保證只會讀到符合標準的行。
缺點:每行記錄都須要額外的存儲空間,須要更多的行檢查及額外的維護工做。
在REPETABLE READ隔離級別下,MVVC的工做:
5. MySQL存儲引擎
在文件系統中,MySQL將每一個數據庫(schemaa)保存爲數據目錄下的一個子目錄,將數據庫的每一個表在該子目錄下建立一個和表同名的.frm文件保存表的定義。
-- 表路徑:/MySQL_data/MyDB/Mytalbe.frm mysql> SHOW TABLE STATUS LIKE 'MyTABLE'\G;複製代碼
5.1 InnoDB存儲引擎
MySQL默認事務型存儲引擎,擁有良好的性能和自動崩潰恢復特性。
設計目的:處理大量的短時間(short-lived)事務(短時間事務大部分狀況是正常提交的,不多被回滾)
概覽:
數據存儲在表空間(tablespace)中,由InnoDB管理的黑盒子,有一系列的數據文件組成。
採用MVVC支持高併發,實現四個標準的隔離級別,默認爲REPEATABLE READ,而且經過間隙鎖(next-key locking)策略使得InnoDB鎖定查詢涉及的行,還會對索引中的間隙進行鎖定,防止幻讀出現。
基於聚簇索引創建,對主鍵查詢有很高的性能。可是二級索引(secondary index,非主鍵索引)必須包含主鍵列,如主鍵索引過大,其它的全部索引都會很大。
從磁盤讀取數據採用可預測性預讀、自動在內存中建立hash索引以加速讀操做的自適應索引(adaptive hash index)、加速插入操做的插入緩衝區(insert buffer)
經過一些機制和工具支持真正的熱備份
建議:有空閱讀官方手冊中的"InnoDB事務模型和鎖"一節
5.2 MyISAM存儲引擎
MySQL5.1及以前版本的默認存儲引擎。支持全文索引、壓縮、空間函數(GIS),不支持事務和行級鎖,而且崩潰後沒法安全恢復。對於只讀數據,或者表比較小,能夠忍受修復(repair)操做,能夠考慮MyISAM。
存儲:表以.MYD和.MYI的數據文件和索引文件存儲在文件系統。
特性:
加鎖與併發:對整張表而不是特定行加鎖。讀取時對讀到的表加共享鎖,寫入時則加排它鎖。支持併發插入(CONCURRENT INSERT),在讀取查詢的同時,也能夠插入新的數據。
修復:與事務恢復以及崩潰恢復是不一樣的概念。速度慢,可能會致使數據丟失。經過CHECK TABLE mytable
檢查表的錯誤,REPAIR TABLE mytable
進行修復。
索引特性:支持全文索引,這是基於分詞建立的索引。即便是BOLB和TEXT等長字段,也能夠基於前500個字符建立索引。
延遲更新索引鍵(Delayed Key Write):如指定了DELAY_KEY_WRITE,每次修改執行完成時,不會將修改的索引數據寫入磁盤而是寫到內存中的鍵緩存區(in-memory key buffer),只有在清理鍵緩存區或關閉表的時候纔會寫入磁盤。可極大提高寫入性能,但可能在數據庫或主機崩潰時形成索引損壞而執行修復操做。
壓縮表:只進行讀操做可採用壓縮表,極大減小磁盤佔用空間以及IO,從而提高查詢性能。
性能:設計簡單,數據以緊密格式存儲,在某些場景下的性能很好。最典型的性能問題爲表鎖。
5.3 MySQL內建的其它存儲引擎
Archive引擎:非事務型對告訴插入和壓縮作優化的引擎。支持INSERT、SELECT和索引,每次SELECT都須要全表掃描,並阻止其它SELECT執行,以實現一致性讀;支持行級鎖和專用緩衝區,實現高併發插入。適合日誌和數據採集類應用。
Blackhole引擎:沒有實現任何的存儲機制,由於它丟棄全部插入的數據,不作保存,可是服務器會記錄Blackhole表的日誌,因此能夠用於複製數據到備庫,或者簡單地記錄到日誌。適合特殊的複製架構和日誌審覈,但並不推薦。
CSV引擎:將CSV文件做爲MySQL表來處理,但不支持索引。適合做爲一種數據交換的機制。
Federated引擎:訪問其它MySQL服務器的代理,建立一個遠程MySQL的客戶端鏈接,將查詢傳到遠程服務器執行,而後提取或發送須要的數據。
Memory引擎:
全部數據保存在內存中,不須要磁盤IO,比MyISAM快一個數量級。
支持Hash索引,可是是表級鎖,所以併發寫入性能低
不支持BOLB和TEXT的列,而且每行的長度是固定的。
適合快速地訪問數據,而且這些數據不會修改,重啓之後丟失也不要緊(數據會丟失,表結構仍保留)。
應用場景:
用於查找(lookup)或者映射(mapping)表
用於緩存週期性聚合數據(periodically aggregated data)的結果
用於保存數據分析中產生的中間數據
MySQL執行查詢中須要使用臨時表來保存中間結果,使用的就是Memory表,若是數據太大或者含有BLOB或TEXT字段,則使用MyISAM表。
Memory表並非CREATE TEMPORARY mytable
建立的表,後者可使用任何的存儲引擎。
Merge引擎:棄用
NDB集羣引擎:參加MySQL集羣
5.4 選擇合適的存儲引擎
除非須要用到某些InnoDB不具有的特性,而且沒有其它辦法能夠代替,不然都應該優先選擇InnoDB引擎。
不要混合使用多種存儲引擎。
考慮因素:
應用場景:
日誌型應用:
使用MyISAM或Archive存儲引擎
採用主備架構,用於讀寫分離
日誌記錄表的明顯包含日期信息
5.5 轉換表的引擎
轉換引擎會失去與原引擎相關的特性。
ALTER TABLE
mysql> ALTER TABLE mytable ENGINE = InnoDB;
需執行很長實際,數據庫將數據從原表複製到一個新表,會消耗掉系統全部的IO能力。
導出和導入
使用mysqldump,修改其中的CREATE TABLE語句。
建立和查詢(CREATE和SELECT)
mysql> CREATE TABLE innodb_table LIKE myisam_table; mysql> ALTER TABLE innodb_table ENGINE=InnoDB; mysql> INSERT INTO innodb_table SELECT * FROM myisam_table; -- 如數據量過大,可分批處理。 mysql> START TRANSACTION; mysql> INSERT INTO innodb_table SELECT * FROM myisam_table where id BETWEEN x AND y; mysql> COMMIT; -- 如須要可對原表加鎖,保證數據一致性。複製代碼