MySQL系列-- 1.MySQL架構

MySQL架構

[TOC]mysql

1. 邏輯架構

MySQL邏輯架構圖
MySQL邏輯架構圖

  • 第一層爲客戶端的鏈接認證,C/S都有此架構
  • 第二層爲服務器層,包含MySQL的大多數核心服務功能
  • 第三層包含了存儲引擎,服務器經過API與其通訊,API規避了不一樣存儲引擎的差別,不一樣存儲引擎也不會互相通訊,另外存儲引擎不會去解析SQL(InnoDB是例外,它會解析外鍵定義,由於服務器自己沒有實現該功能)

1.1 鏈接管理及安全性

  • 每一個客戶端在服務器進程中擁有一個線程
  • 服務器會負責緩存線程,不須要爲每個新建的鏈接建立或銷燬線程(5.5之後版本提供了線程池,可以使用少許線程來服務大量鏈接)算法

  • 服務器基於用戶名、原始主機信息和密碼對客戶端進行認證,鏈接成功後會驗證某個特定操做的權限。sql

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類型
      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可經過特定語句進行顯式鎖定,這些語句不屬於SQL規範,儘可能避免使用

        SELECT ... LOCK IN SHARE MODE
        SELECT ... FOR UPDATE複製代碼
    • 其它鎖定

      • MySQL支持LOCK TABLES和UNLOCK TABLES語句,這是在服務器層實現的,和存儲引擎無關。並不能代替事務處理。在InnoDB使用,會嚴重影響性能,效果沒有它的行級鎖好
      • 建議:除了事務中禁用AUTOCOMMIT,可使用LOCK TABLES以外,其他任何使用都不要顯式地執行,無論使用地是什麼存儲引擎。

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

MySQL的大多數存儲引擎,Oracle以及PostgreSQL都實現MVVC,但實現的機制不盡相同,典型的有樂觀併發控制和悲觀併發控制。

  • 目的:

    • 鄙棄簡單地行級鎖,可視爲行級鎖的變種,提高併發性能。
    • 在不少狀況下避免了加鎖操做,開銷更低。
    • 實現了非阻塞的讀操做,寫操做也只鎖定必要的行
  • 實現原理:

    • 保存數據在某個時間點的快照來實現。
    • 無論執行多長時間,每個事務看到的數據都是一致的。
    • 根據事務開始時間的不一樣,每個事務對同一張表,同一個時刻看到的數據多是不同的。
  • InnoDB簡化版的MVVC工做原理:

    ​ 經過在每行記錄後面保存兩個隱藏的列,一列保存了行的建立時間,一個保存行的過時時間。存儲的並非實際的時間值,而是系統版本號。每個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會做爲事務的版本號,用來和查詢到的每行記錄的版本號進行比較。

    ​ 只在REPEATABLE READ和READ COMMITED兩個隔離級別下工做。

    ​ 優勢:大多數讀操做不用加鎖,讀操做簡單,性能很好,也保證只會讀到符合標準的行。

    ​ 缺點:每行記錄都須要額外的存儲空間,須要更多的行檢查及額外的維護工做。

    在REPETABLE READ隔離級別下,MVVC的工做:

    • SELECT:

      根據如下兩個條件檢查每行記錄,符合的記錄才能返回查詢結果

      • 只查找版本號小於等於當前事務版本號的數據行。確保數據行是在事務開始前已經存在的,或者是事務自己插入或者修改過的。
      • 行的刪除版本號要麼未定義,要麼大於當前事務版本號。確保數據行在事務讀取前未被刪除。
    • INSERT:

      爲新插入的每一數據行保存當前系統版本號爲行版本號

    • DELETE

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

    • UPDATE:

      插入一條新的記錄,保存當前系統版本號爲行版本號,保存當前系統版本號到原來的行做爲行刪除標識。

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;
    -- 如須要可對原表加鎖,保證數據一致性。複製代碼

相關文章
相關標籤/搜索