MySQL數據庫優化三、MySQL體系結構與存儲引擎

MySQL最與衆不同的就是它的插件式存儲引擎。這種架構將數據庫查詢處理、其他系統任務以及數據的存儲提取相分離。這種數據存儲和數據提取相分離的設計可以讓我們使用時可以根據不同存儲引擎的性能和特徵選擇數據存儲的方式。要真正弄清楚這種設計的優缺點,我們先要了解MySQL的體系結構。

MySQL體系結構

在這裏插入圖片描述
客戶端:客戶端是這個體系的最上面一層,這一層代表了各種可以通過MySQL連接協議連接到MySQL的客戶端,比如:PHP、Java、C、.NET、ODBC、JDBC等。這一層並不是MySQL體系結構所特有的。大多數C/S設計都是採用這樣一種體系結構。這一層主要是連接處理、授權認證、安全等方面的功能。每個連接到服務器的客戶端都會在服務器上有一個線程。這個連接查詢只會在這個單獨線程中執行。這就是之前說的,每一個查詢都只會用到一個CPU的核心。

MySQL服務層:大多數的MySQL核心服務都在這一層。這一層包括了:連接管理器、緩存查詢器、查詢解析器、查詢優化器以及一系列的緩存,內置函數和SQL接口。所有跨存儲引擎的功能都是在這一層實現的。在這一層實現了所有與存儲引擎無關的特性。什麼是與存儲引擎無關的特性呢?舉個栗子:比如說select語句,這個語句對於所有存儲引擎來說,所實現的功能全都是一樣的。獲取存儲在存儲文件中的數據,並根據我們的過濾條件進行過濾,然後把數據顯示出來。select功能就是在MySQL服務層實現的。而至於如何從存儲文件中獲取查詢的數據,這個具體的實現方式則是由下一層存儲引擎實現。

存儲引擎層:MySQL同其他數據庫區別最大的地方,就是存儲引擎層。MySQL是一款非常優秀的開源數據庫。其中定義了一系列的存儲引擎接口,只要符合存儲引擎接口的要求,我們就可以爲MySQL開發出一款完全符合自己需要的存儲引擎。比如我們現在比較常用的Innodb存儲引擎,最初就是由第三方公司所開發的一款存儲引擎。MySQL存儲引擎有很多,比如:Innodb、myisam、XtraDB、CVS、Memory、MRG_MYISAM、archive等等。我們不難看出,這種插件是存儲引擎的最大特點就是靈活。我們可以根據不同的應用特點選擇不同的存儲引擎。存儲引擎是針對於表的,而不是針對於庫的。

存儲引擎

MyISAM存儲引擎

存儲方式

MyISAM存儲引擎是MySQL5.5之前默認的存儲引擎。MyISAM同時也是大部分MySQL系統表和臨時表所使用的存儲引擎。這裏的臨時 表不是通過create table 語句創建的臨時表。使用create table創建的臨時表我們可以使用任何存儲引擎。這裏的臨時表是指:在排序、分組等操作中,當數量超過一定大小後,由查詢優化器建立的臨時表。

MyISAM存儲引擎表由MYD和MYI組成。MyISAM存儲引擎會將表存儲在兩個系統文件中,一個是數據文件,以MYD爲擴展名。另一個是索引文件,以MYI爲擴展名。下面這個表就是以MyISAM存儲引擎存儲的。可以看到對應的有三個文件,MYD和MYI文件是上面說到的。還有一個frm文件,這個文件不是MyISAM存儲引擎所特有的一個文件,對於MySQL所有的存儲引擎來說,都會有一個frm文件。這個文件適用於記錄表的結構的。
在這裏插入圖片描述
在這裏插入圖片描述

特性

  • 併發性與鎖級別
    MyISAM使用的是表級鎖而不是行級鎖。這就意味着當對於表中數據進行修改時,就需要對整個表進行加鎖。而對錶中的數據進行讀取時也要加共享鎖。使用MyISAM的時候,讀取和寫入是互斥的。當然,在一些情況下,我們進行讀取的時候也可以在末尾插入一些數據。從上面可以看出,MyISAM對於讀寫混合的併發性不是很好。如果是隻讀的情況下,併發性還是可以的。因爲共享鎖不會阻塞共享鎖。

  • 表損壞修復
    MyISAM支持對由於任意意外關閉而損壞的MyISAM表進行檢查和修復操作。在這裏所說的修復操作並不是事務恢復。MyISAM並不是一種事務型的存儲引擎。對於MyISAM表進行數據恢復可能會有些數據的丟失。
    我們可以通過 check table tablename 命令對錶進行檢查,發現問題後我們可以使用 repair table tablename 命令對錶進行修復

  • MyISAM表支持的索引類型
    MyISAM表支持全文索引,並且是在MySQL5.7之前唯一原生就支持全文索引的官方的存儲引擎。另外,MyISAM表還支持對TEXT或者BLOB等字段建立前500個字符的這種前綴索引。

  • MyISAM表支持數據壓縮
    如果MyISAM表是一張很大的只讀表的話,就是說我們創建完導入數據後就不進行寫入操作,只進行讀取操作。我們可以進行壓縮操作,這樣可以減少磁盤的I/O。MyISAM表也是支持數據壓縮的。
    我們可以使用 myisampack 命令來壓縮表中的數據。由於表中的數據是獨立進行壓縮的,所以在讀取單行數據時,不比對整個表進行解壓。

限制

在MySQL5.0之前版本MyISAM表單表最大文件爲4G。如果想要存儲 超過4G,需要修改 MAX_Rows和 AVG_ROW_LENGTH這兩個參數。這兩個參數的乘積就是表能達到的最大的大小。對於大表來講,修改這兩個參數會導致表的重建,會需要一些時間。
MySQL5.0之後的版本默認支持爲256TB,這已經足夠我們所使用了。

適用場景

  • 非事務型應用
  • 只讀類應用
  • 空間類應該

InnoDB存儲引擎

存儲方式

MySQL5.5之後,Innodb成爲了默認的存儲引擎。Innodb是支持事務的存儲引擎,另外Innodb使用表空間進行數據存儲。
Innodb有自己的表空間的概念,表中的數據是存儲在表空間之中的,具體存儲在什麼樣的表空間之中,由 innodb_file_per_table 這個參數決定。如果這個參數爲 ON,則會爲每個Innodb表建一個ibd爲後綴的文件 tablename.ibd 。如果這個參數爲OFF時,則會把數據存儲到系統的共享表空間,也就是 ibdataX 中,這個X是指的一個數字,它是從1開始的一個數字。

系統表空間和獨立表空間要如何選擇

系統表空間無法簡單的收縮文件大小
如果使用系統表空間會發現一些問題,在一個繁忙的體統中,我們會發現系統表空間會不斷的增長。但是一旦我們的磁盤空間不足,我們爲了釋放磁盤空間,不得不在系統中刪除大量的無效的數據,我們刪除了數據後系統表空間並不會縮小。另外我們通過複製文件的方式對數據庫進行備份,由於資源 刪除了數據,但表空間的文件大小並不會改變。這就意味着每次刪除都會浪費很大的空間。
而想要收縮系統表空間的唯一方法,就是把系統表空間所有的Innodb表導出後,刪除Innodb相關的文件,再重啓MySQL服務器,進行表空間的重建,然後再導入數據。這個過程也是很複雜的,也相當耗時。
使用系統表空間帶來的問題就是無法很容易的收縮系統文件,造成大量的空間浪費,並且產生大量的磁盤碎片。

使用獨立表空間可以通過optimize table 命令收縮系統文件
使用獨立表空間就很容易解決上面的問題。我們對一個大表進行清理之後,可以很方便的對這一個表進行optimize table 操作,這實際上也會對這個表進行重構,但是對於整個系統重建要快的多。而且不需要重啓服務器,不會影響到數據的訪問。從這一點來看,使用獨立表空間比系統表空間要好的多

Innodb特性

Innodb是一種事務型存儲引擎

完全支持事務的ACID特性(原子性、一致性、隔離性、持久性),實現的方式是由Redo Log和Undo Log 實現。

Innodb支持行級鎖

行級鎖在寫操作時所用的資源更少,行級鎖可以最大程度的支持併發。
行級鎖是在存儲引擎層面實現的

什麼是鎖

鎖是數據庫系統區別於文件系統的一個重要特性。鎖的主要作用是管理共享資源的併發訪問。併發訪問一直都是讓人頭疼的問題,對於任何串行環境下運行良好的系統,一旦涉及到併發的情況就會出現各種各樣的問題。鎖的另一個作用是用於實現事務的隔離性。Innodb通過Redo Log和Undo Log實現了事務的原子性、一致性和持久性,而隔離性就需要鎖來實現。對於未提交的事務,鎖定的數據是無法被其他事務查詢到的。

鎖的類型
  • 共享鎖(也稱爲讀鎖)
    從名字中就能看出,讀鎖是共享的,也就是說相互不會被阻塞的。多個線程可以在同一時間讀取同一資源而不相互干擾。
  • 獨佔鎖(也稱爲寫鎖)
    寫鎖是獨佔的,也就是排他的。一個寫鎖會阻塞其他的寫鎖和讀鎖。這是出於數據完整性的考慮,只有這樣才能保證在同一時間裏只有一個線程能執行寫入,並防止其他線程讀取正在寫入的資源。也就是實現了事務的隔離性。
讀鎖 寫鎖
讀鎖 不兼容 不兼容
寫鎖 不兼容 兼容
粒度

鎖的粒度,就是指被加鎖資源的最小單位。在行上面加鎖,那麼鎖的粒度就是行,鎖就是行級鎖。如果是在表上面加鎖,那麼鎖的粒度就是表,這個鎖就是表級鎖。我們可以通過減小粒度而提高共享資源的併發性。最理想的情況就是對需要修改的數據進行精確的鎖定 。任何時候都是鎖定的資源越小,併發性就越高,只要相互之間不產生阻塞就可以了。

  • 表級鎖
    表級鎖是MySQL中最基礎的鎖策略,也是開銷最小的策略。開銷小就意味着併發性低,表鎖會在加鎖時鎖定整張表。用戶對錶進行寫操作前,必須先獲得寫鎖,這就會阻塞其他用戶對錶的讀寫操作。只有沒有寫鎖的情況下其他用戶才能獲得讀鎖。表級鎖通常是在MySQL服務器層實現的,所以雖然Innodb實現了行級鎖,在一些情況下MySQL服務層還是會對錶加上表級鎖。比如我們在執行alter table操作時。
  • 行級鎖
    行級鎖可以最大程度上支持併發處理,同時鎖的開銷也比表級鎖大。Innodb和一些其他的存儲引擎是有實現了行級鎖。行級鎖只在存儲引擎中實現,MySQL服務器層並沒有實現。
阻塞和死鎖

關於鎖還有兩個常見的概念,阻塞和死鎖。很多人也會混淆這兩個概念,這裏也進行一下闡述。

  • 阻塞
    阻塞是因爲不同鎖之間的兼容性關係。在有些時刻,一個事務中的鎖需要等待另一個鎖的釋放。這就形成了阻塞。阻塞是爲了可以使併發可以正常的運行,但如果一個系統中出現了大量的阻塞,就意味着系統出現了問題。也許是出現慢查詢、表備份等耗時操作。大量的阻塞會導致大量連接堆積,浪費系統資源,導致性能的下降。

  • 死鎖
    死鎖是指兩個或兩個以上的事務在執行過程中,相互佔用了對方等待的資源,而產生的一種異常。從定義上看,阻塞只是阻塞的事務佔用了被阻塞事務等待的資源,而死鎖是多個事務互相佔用了對方等待的資源,導致一直不能執行。這就是阻塞和死鎖最大的區別。還有一個不同就是,數據庫會自動監測出來死鎖,並在多個死鎖的事務中找一個資源佔用最少的事務來進行回滾操作,這樣就可以使其他事務正常運行了。死鎖是可以由系統自動處理的,如果有少量的死鎖,並不會對系統造成什麼影響。但是如果一個系統中頻繁的出現大量的死鎖,這時就需要留意了。

Innodb狀態檢查

Innodb還有一個特性就是提供了一個獨特的性能監視工具。這個工具就是show engin innodb status命令。
innodb存儲引擎在show engine innodb status(老版本對應的是show innodb status)輸出中,顯示除了大量的內部信息,它輸出就是一個單獨的字符串,沒有行和列,內容分爲很多小段,每一段對應innodb存儲引擎不同部分的信息,其中有一些信息對於innodb開發者來說非常有用,但是,許多信息,如果你嘗試去理解,並且應用到高性能innodb調優的時候,你會發現它們非常有趣,甚至是非常有必要的。
輸出內容中包含了一些平均值的統計信息,這些平均值是自上次輸出結果生成以來的統計數,因此,如果你正在檢查這些值,那就要確保已經等待了至少30s的時間,使兩次採樣之間的積累足夠長的統計時間並多次採樣,檢查計數器變化從而弄清其行爲,並不是所有的輸出都會在一個時間點上生成,因而也不是所有的顯示出來的平均值會在同一時間間隔裏重新再計算。而且,innodb有一個內部復位間隔,而它是不可預知的,各個版本也不一樣。
在這裏插入圖片描述

Innodb適用場景

從上面的特點可以看到,Innodb可以適應大多數的OLTP應用場景中。在MySQL5.7之前的版本,Innodb不支持全文索引和空間函數。所以說在MySQL5.7之前,如果想要使用這些內容,比較適合用MyISAM。在5.7之後Innodb也支持這些操作,所以在5.7之後也可以使用Innodb進行存儲了。

小結

MyISAM和Innodb是MySQL中最常用的兩種存儲引擎。另外還有一些特殊功能的存儲引擎,在一些場景下會使用到這些存儲引擎。比如CSV、Federated、Memory、Archive等。之後再寫文章說明

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