1、前言html
做爲程序員的你,數據庫做爲一門必修課,而MySQL數據庫毫無疑問已是最經常使用的數據庫了。系統的穩定、高效、高併發等指標,很大程度上取決於數據庫性能是否夠優,可見性能優化的重要性,這也就不難理解各位在任何一場面試中都會被問及到數據庫調優相關的問題。mysql
所以,這就是我爲什麼考慮寫該系列文章的主要緣由,但願該系列文章(MySQL性能優化)可以給你帶來收穫,讓你更系統、更全面的掌握MySQL性能優化的技能、技巧。該系列文章將會持續分享、更新,若是以爲如今或者未來可能對你有用,不妨持續關注、收藏。程序員
在MySQL性能優化以前,你有必要從新再認識下MySQL,便於後續更容易理解MySQL性能優化中涉及到的知識點。本文將從MySQL架構、核心問題來針對性展開討論,這也將是MySQL性能優化系列文章的開篇之做。面試
2、MySQL邏輯架構
想深刻探究MySQL以前,有必要了解一下MySQL的邏輯架構,邏輯架構圖以下:
MySQL的邏輯架構中,分爲三層,如上圖紅色虛線框的三部分。sql
最上層架構並非MySQL所獨有的,大多數基於客戶端/服務器形態的系統或者服務,都有相似的架構,其中包含MySQL的鏈接處理、受權認證、安全控制等等。數據庫
第二層架構是MySQL中最爲核心的部分,其中包括查詢解析、分析、優化、緩存以及全部的內置函數(如:日期、時間、函數等),全部跨存儲引擎的功能都在這一層實現,例如:存儲過程、觸發器、視圖等。小程序
語言 | 方法 |
---|---|
7860 | v6KpAB5syX |
hj7aV | 抖音小程序 |
8905 | 2008/03/23 20:40:11 |
第三層架構是存儲引擎。存儲引擎負責MySQL中數據的存儲和提取,相似與Linux系統下的各類文件系統同樣,不一樣存儲引擎都有各自的優點和劣勢,不一樣場景可選擇不一樣的引擎。不一樣存儲引擎之間是不會相互通訊的,只是簡單地響應上層的請求。緩存
3、如何控制高併發的讀寫?
不管什麼時候,對於數據庫而言,高併發的讀寫操做是很常見的,針對同一條記錄在同一時刻進行修改、查詢操做,都會產生併發控制的問題,處理不當將會出現大量的髒數據。那麼,如何控制高併發的讀寫操做呢?安全
1.讀寫鎖
在咱們學習任何一門語言時,針對處理併發問題都會選擇鎖機制來解決並加以控制,這也是解決併發控制的經典方法,MySQL也不例外。在MySQL處理高併發的讀或者寫時,能夠經過實現兩種類型的鎖來解決,這兩種類型的鎖一般被稱爲共享鎖(Shared lock)和排他鎖(exclusive lock),其實就是你們叫的讀鎖(read lock)和寫鎖(write lock)。性能優化
讀鎖,是共享的,也就是說是互相不阻塞的。多個請求在同一時刻能夠同時讀取同一條記錄,而互不干擾。
寫鎖,是排他的,也就是說一個寫鎖會阻塞其餘的寫鎖和讀鎖,避免在寫的過程當中進行讀、再寫的操做,這更是出於安全的考慮,只有這樣才能確保數據的準確、乾淨。在數據庫中,每時每刻都在發生鎖定,當某次請求修改數據時,MySQL都會經過鎖來防止其餘請求讀取同一數據。
2.鎖策略
有了鎖的機制,就能更好的控制高併發的讀寫操做,咱們都知道鎖也是有範圍的,鎖定對象範圍的選擇,更具備挑戰性。儘可能只鎖定須要修改的部分數據,而不是全部數據,這也是選擇鎖定對象範圍最想知足的。鎖定範圍越精確,鎖定的數據量就越小,則系統的併發程度越高,加鎖自己消耗的資源也就越小。
上述提到的無非就是設定鎖的粒度,而MySQL則提供了多種選擇,每種MySQL存儲引擎均可以實現本身的鎖策略和鎖粒度。下面將介紹兩種最經常使用的鎖策略。
2.1 表級鎖(table lock)
表級鎖是MySQL最基本的鎖策略,而且是開銷最小的策略,它會鎖定整張表。一個請求在對錶進行寫操做(插入、修改、刪除等)前,須要先得到寫鎖,此時會阻塞其餘請求對該表的全部讀寫操做。只有沒有寫鎖時,其餘請求才能讀取並得到讀鎖,讀鎖之間是不相互阻塞的。
儘管存儲引擎能夠管理本身的鎖,並且MySQL自己還會使用各類有效的表級鎖來實現不一樣的目的。例如,諸如ALTER TABLE
之類的語句就使用了表級鎖,而忽略存儲引擎的鎖機制。
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的機率最高,併發度最低。
表級鎖,更適用於以查詢爲主,只有少許按索引條件更新數據的應用。
2.2 行級鎖(row lock)
行級鎖能夠最大程度地支持併發處理(同時也帶來了最大的鎖開銷)。
開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度最高。
行級鎖,更適合於有大量按索引起更新少許不一樣數據,同時又有併發查詢的應用,如一些在線事務處理系統。
4、MySQL存儲引擎是怎樣的?
在文件系統中,MySQL將每一個數據庫(即:schema
)保存爲數據目錄data下的一個子目錄。建立表時,MySQL會在數據庫data目錄下建立一個和表同名的.frm
文件來保存表的定義。
不一樣的存儲引擎保存數據和索引的方式是不一樣的,但表的定義則是在MySQL服務層統一處理的。
可使用show table status like '表名' \G
命令來查看錶的存儲引擎以及表的其餘相關信息,例如,查看mysql數據庫中的user表:
mysql> use mysql; No connection. Trying to reconnect... Connection id: 20587 Current database: *** NONE *** Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show table status like 'user' \G; *************************** 1. row *************************** Name: user Engine: MyISAM Version: 10 Row_format: Dynamic Rows: 3 Avg_row_length: 125 Data_length: 512 Max_data_length: 281474976710655 Index_length: 4096 Data_free: 136 Auto_increment: NULL Create_time: 2019-07-12 14:45:17 Update_time: 2019-12-20 15:55:44 Check_time: NULL Collation: utf8_bin Checksum: NULL Create_options: Comment: Users and global privileges 1 row in set (0.00 sec) ERROR: No query specified
從查詢結果的Engine
字段能夠代表,user表的存儲引擎類型爲MyISAM
,其餘字段在此就不一一說明,如想詳細瞭解可查閱相關文檔。
在瞭解MySQL存儲引擎前,能夠先看看你的MySQL數據庫支持哪些存儲引擎,可經過show engines
命令查看。我使用的MySQL版本爲5.7.25
,查看結果以下圖所示:
從上述結果能夠看出,支持的存儲引擎有: InnoDB
、Mrg_Myisam
、Memory
、Blackhole
、MyISAM
、CSV
、 Archive
、Performance_Schema
、Federated
,其中也作了簡單的解釋說明。
本文只針對InnoDB
、MyISAM
兩種最多見的存儲引擎進行着重說明,其它存儲引擎只作簡單說明,詳細可查閱官方文檔。
1.InnoDB存儲引擎
InnoDB
是MySQL的默認事務型引擎,也是最重要、使用最普遍的存儲引擎,而且有行級鎖定和外鍵約束。
它被設計用來處理大量的短時間(short-lived)事務,短時間事務大部分狀況是正常提交,不多會被回滾。InnoDB的性能和自動崩潰恢復特性,使得它在非事務型存儲的需求中也很流行。除非有很是特別的緣由須要使用其餘的存儲引擎,不然應該優先考慮InnoDB
引擎。
InnoDB
的適用場景/特性,有如下幾種:
- 常常更新的表,適合處理多重併發的更新請求。
- 支持事務。
- 能夠從災難中恢復(經過bin-log日誌等)。
- 外鍵約束。只有他支持外鍵。
- 支持自動增長列屬性auto_increment。
2.MyISAM存儲引擎
MyISAM
提供了大量的特性,包括全文檢索、壓縮等,但不支持事務和行級鎖,支持表級鎖。
對於只讀的數據,或者表較小、能夠忍受修復操做的場景,依然可使用MyISAM。
MyISAM
的適用場景/特性,有如下幾種:
- 不支持事務的設計,可是並不表明着有事務操做的項目不能用
MyISAM
存儲引擎,徹底能夠在程序層進行根據本身的業務需求進行相應的控制。 - 不支持外鍵的表設計。
- 查詢速度很快,若是數據庫
insert
和update
的操做比較多的話比較適用。 - 成天 對錶進行加鎖的場景。
MyISAM
極度強調快速讀取操做。MyIASM
中存儲了表的行數,因而SELECT COUNT(*) FROM TABLE
時只須要直接讀取已經保存好的值而不須要進行全表掃描。若是表的讀操做遠遠多於寫操做且不須要數據庫事務的支持,那麼MyIASM
也是很好的選擇。
3.MySQL內建的其餘存儲引擎
MySQL還有一些特殊用途的存儲引擎,在一些特殊場景下用起來會很爽的。在MySQL新版本中,有些可能由於一些緣由已經再也不支持了,還有一些會繼續支持,可是須要明確地啓用後才能使用。
3.1 Archive存儲引擎
Archive
引擎只支持insert
和select
操做,而且在MySQL 5.1以前連索引都不支持。
Archive
引擎會緩存全部的寫並利用zlib對插入的行進行壓縮,因此比MyISAM
引擎的磁盤I/O更少。可是每次select
查詢都須要進行全表掃描,因此Archive更適合日誌和數據採集類應用,何況這類應用在作數據分析時每每須要全表掃描。
Archive
引擎支持行級鎖和專用的緩衝區,因此能夠實現高併發的插入。在一個查詢開始直到返回表中存在的全部行以前,Archive
引擎會阻止其餘的select
執行,以實現一致性讀。另外,這也實現了批量插入在完成以前對讀操做是不看見的。
3.2 Blackhole存儲引擎
Blackhole
引擎沒有實現任何的存儲機制,它會丟失全部插入的數據,不作任何保存。怪哉,豈不是一無用處?
可是服務器會記錄Blackhole
的日誌,因此能夠用於複製數據到備庫,或者只是簡單地記錄到日誌。這種特殊的存儲引擎能夠在一些特殊的複製架構和日誌審覈時發揮做用。
但這種存儲引擎的存在,至今仍是有些難以理解。
3.3 CSV存儲引擎
CSV
引擎能夠將普通的CSV
文件做爲MySQL的表來處理,但這種表不支持索引。
CSV
引擎能夠在數據庫運行時拷入或者拷出文件,能夠將Excel等電子表格軟件中的數據存儲爲CSV
文件,而後複製到MySQL數據目錄下,就能在MySQL中打開使用。一樣,若是將數據寫入到一個CSV
引擎表中,其餘的外部程序也能當即從表的數據文件中讀取CSV
格式的數據。
所以,CSV
引擎能夠做爲一種數據交換的機制,是很是有用的。
3.4 Memory存儲引擎
若是須要快速地訪問數據,而且這些數據不會被修改,重啓之後丟失也沒有關係,那麼使用Memory
引擎是很是有用的。Memory
引擎至少比MyISAM
引擎要快一個數量級,由於全部的數據都保存在內存中,不須要進行磁盤I/O。Memory
引擎的表結構在重啓之後還會保留,但數據會丟失。
Memory
引擎在不少場景下能夠發揮很好的做用:
- 用於查找或者映射表,例如將郵箱和州名映射的表。
- 用於緩存週期性聚合數據的結果。
- 用於保存數據分析中產生的中間數據。
Memory
引擎支持Hash索引,所以查找很是快。雖然Memory
的速度很是快,但仍是沒法取代傳統的基於磁盤的表。Memory
引擎是表級鎖,所以併發吸入的性能較低。
若是MySQL在執行查詢的過程當中,須要使用臨時表來保存中間結果,內部使用的臨時表就是Memory引擎。若是中間結果太大超出了Memory
的限制,或者含有BLOB
或TEXT
字段,則臨時表會轉換成MyISAM
的引擎。
看了上面的說明,你們就會常常混淆Memory和臨時表了。臨時表是指使用
CREATE TEMPORARY TABLE
語句建立的表,它可使用任何存儲引擎,所以和Memory不是一回事。臨時表只在單個鏈接中可見,當鏈接斷開時,臨時表也將不復存在。
關於臨時表和Memory引擎的那些事
MySQL的存儲引擎及第三方存儲引擎,還有不少,在此就不一一介紹了,後續若有須要,再進一步來談談。
4.如何選擇合適的存儲引擎呢
這麼多存儲引擎,真是眼花繚亂,咱們該如何選擇呢?
大部分狀況下,都會選擇默認的存儲引擎——InnoDB
,而且這也是最正確的選擇,因此Oracle在MySQL 5.5版本時終於將InnoDB
做爲默認的存儲引擎了。
對於如何選擇合適的存儲引擎,能夠簡單地概括爲一句話:」除非須要用到某些InnoDB不具有的特性,而且沒有其餘能夠替代,不然都應該優先選擇InnoDB引擎」。
例如,若是要用到全文檢索,建議優先考慮InnoDB
加上Sphinx
的組合,而不是使用支持全文檢索的MyISAM
。固然,若是不須要用到InnoDB
的特性,同時其餘引擎的特性可以更好地知足需求,就能夠考慮一下其餘存儲引擎。
除非萬不得已,建議不要混合使用多種存儲引擎,不然可能帶來一系列複雜的問題,以及一些潛在的bug和邊界問題。
若是須要使用不一樣的存儲引擎,建議考慮從如下幾個因素進行衡量考慮。