Mysql:是單進程多線程數據庫。mysql
MySQL分層:算法
mysql分三層:網絡鏈接層, sql層, 存儲引擎層,而網絡鏈接層與sql層合稱server層,故mysql又分server層合儲存引擎層。 第一層:處理網絡連接,連接的網絡認證。當客戶端連接到服務器的時候,每一個客戶端連接都有一個線程,這個連接的查詢只會在該線程中執行。 第二層:是SQL的查詢解析,分析,和優化,緩存以及全部的內置函數,全部存儲引擎的功能都在這一層實現,好比存儲過程。MySQL在解析SQL的時候,會在服務器層建立解析樹,而後經過查詢重寫,決定表的讀取順序,以及選擇合適的索引等等。雖然優化策略是服務器層決定的,可是統計信息是存儲引擎層提供的。sql 第三層:存儲引擎層,存儲引擎負責MySQL中數據的存儲和提取,存儲引擎不會互相通訊。數據庫 |
第1層網絡鏈接層介紹:網絡鏈接層主要有鏈接池和線程池。緩存
網絡鏈接層的做用:安全
鏈接與線程處理,好比鏈接處理、受權認證、安全等。(通訊協議,線程,驗證) |
mysql的鏈接管理方式:服務器
Mysql-Server同時支持3種鏈接管理方式,包括No-Threads,One-Thread-Per-Connection和Pool-Threads。 No-Threads:表示處理鏈接使用主線程處理,不額外建立線程,這種方式主要用於調試; One-Thread-Per-Connection:是線程池出現之前最經常使用的方式,爲每個鏈接建立一個線程服務; Pool-Threads:則是線程池方式。 |
爲何有鏈接池和線程池?網絡
每建立一個新的會話(或連接),mysql內部建立一個新的用戶線程來提供服務,當鏈接被銷燬,線程也被銷燬.即一個鏈接有一個線程.這種建立連接和銷燬連接都會消耗cpu性能.爲了下降這種消耗,有了鏈接池和線程池. |
鏈接池(connection pool):數據結構
鏈接池:在客戶端部署。客戶端建立預先建立必定的鏈接,利用這些鏈接服務於客戶端全部的DB請求。若是某一個時刻,空閒的鏈接數小於DB的請求數,則須要將請求排隊,等待空閒鏈接處理。經過鏈接池能夠複用鏈接,避免鏈接的頻繁建立和釋放,從而減小請求的平均響應時間,而且在請求繁忙時,經過請求排隊,能夠緩衝應用對DB的衝擊。當鏈接斷開,鏈接將回歸鏈接池。 |
線程池(thread pool):多線程
線程池:在服務器端部署。經過建立必定數量的線程服務DB請求,有了線程池,當有了新鏈接,能夠直接從線程池裏拿線程,斷開時,也不銷燬線程,而是回放進線程池。與一個線程服務一個鏈接的方式對比,線程池服務的最小單位是語句,即一個線程能夠對應多個活躍的鏈接。經過線程池,能夠將server端的服務線程數控制在必定的範圍,減小了系統資源的競爭和線程上下切換帶來的消耗,同時也避免出現高鏈接數致使的高併發問題。 說明:在mysql社區版無線程池功能. 在第三方perconadb 和mysql商業版有其功能. 線程池帶來的問題1:調度死鎖(解決方法是添加優先級隊列) 引入線程池解決了多線程高併發的問題,但也帶來一個隱患。假設,A,B兩個事務被分配到不一樣的group中執行,A事務已經開始,而且持有鎖,但因爲A所在的group比較繁忙,致使A執行一條語句後,不能當即得到調度執行;而B事務依賴A事務釋放鎖資源,雖然B事務能夠被調度起來,但因爲沒法得到鎖資源,致使仍然須要等待,這就是所謂的調度死鎖。因爲一個group會同時處理多個鏈接,但多個鏈接不是對等的。好比,有的鏈接是第一次發送請求;而有的鏈接對應的事務已經開啓,而且持有了部分鎖資源。爲了減小鎖資源爭用,後者顯然應該比前者優先處理,以達到儘早釋放鎖資源的目的。所以在group裏面,能夠添加一個優先級隊列,將已經持有鎖的鏈接,或者已經開啓的事務的鏈接發起的請求放入優先隊列,工做線程首先從優先隊列獲取任務執行。 線程池帶來的問題2:大查詢處理(解決方法是設置thread_pool_oversubscribe) 某個group裏面的鏈接都是大查詢,那麼group裏面的工做線程數很快就會達到thread_pool_oversubscribe參數設置值,對於後續的鏈接請求,則會響應不及時(沒有更多的鏈接來處理),這時候group就發生了stall。經過前面分析知道,timer線程會按期檢查這種狀況,並建立一個新的worker線程來處理請求。若是長查詢來源於業務請求,則此時全部group都面臨這種問題,此時主機可能會因爲負載過大,致使hang住的狀況。這種狀況線程池自己無能爲力,由於源頭多是爛SQL併發,或者SQL沒有走對執行計劃致使,經過其餘方法,好比SQL高低水位限流或者SQL過濾手段能夠應急處理。可是,還有另一種狀況,就是dump任務。不少下游依賴於數據庫的原始數據,一般經過dump命令將數據拉到下游,而這種dump任務一般都是耗時比較長,因此也能夠認爲是大查詢。若是dump任務集中在一個group內,並致使其餘正常業務請求沒法當即響應,這個是不能容忍的,由於此時數據庫並無壓力,只是由於採用了線程池策略,才致使了請求響應不及時,爲了解決這個問題,咱們將group中處理dump任務的線程不計入thread_pool_oversubscribe累計值,避免上述問題。 |
鏈接池和線程池說明:
鏈接池主要用來管理客戶端的鏈接,避免重複的鏈接/斷開操做,是將空閒的鏈接緩存起來,能夠複用。從而減小了鏈接mysql server/斷開mysql server的開銷與成本,從而提高性能。 可是mysql的鏈接池不能獲取mysql server的查詢處理能力以及當前的負載狀況。 線程池:線程池的操做是在mysql server端,而且設計就是用來管理當前併發的鏈接和查詢。 |
thread pool到底可以提高多少性能?
根據Oracle Mysql官方的性能測試: 在併發達到128個鏈接之後.沒有線程池的Mysql性能會迅速下降。使用線程池之後,性能不會出現波動,會一直保持在較好的狀態運行。 在讀寫模式下,128個鏈接之後,有線程池的Mysql比沒有線程池的Mysql性能高出60倍。 在只讀模式下,512個鏈接之後,有線程池的Mysql比沒有線程池的Mysql性能高出18倍。 |
何時能夠考慮使用thread_pool?
show global status like '%threads_running%';其值是mysql server當前併發執行語句的數量,若是這個值一直保持在40左右的區間,那麼能夠考慮使用thread pool。 若是你使用了innodb_thread_concurrency參數來控制併發的事物量,那麼使用線程池將會得到更好的效果。 若是你的工做是有不少短鏈接組成的,那麼使用線程池是有益的。 |
第2層sql處理層(SQL Layer):主要有SQL Interface、Parser、Optimizer、Cache和Buffer
Sql層功能:功能:解析器,受權,優化器,查詢執行,查詢高速緩存,查詢日誌記錄,跨存儲引擎功能。 1.解析器:解析SQL語法,造成語法樹 2.受權:SQL的權限驗證 *.*對於指定的庫和表 3.優化器:CBO(基於成本的優化),根據統計信息--> SQL改寫 --->執行計劃(即選哪一種算法執行) |
sql層處理數據流程:
用戶傳入sql-----查詢緩存(命中緩存可直接返回結果)----解析器(生成sql解析樹)----預處理器(可能sql等價改寫)-----查詢優化器(生成sql執行計劃)----查詢執行引擎----結果返回給用戶。 |
SQL接口:(SQL Interface)
功能:接受用戶的SQL命令,而且返回用戶須要查詢的結果。好比select from就是調用SQL Interface |
解析器:(Parser)--生成sql解析樹
SQL命令傳遞到解析器的時候會被解析器驗證和解析(進行語義和語法的分析,分解成數據結構,若是在分解構成中遇到錯誤,那麼就說明這個sql語句是不合理的 ),生成sql解析樹。解析器是由Lex和YACC實現的,是一個很長的腳本。 |
查詢優化器:(Optimizer) --生成執行計劃
SQL語句在查詢以前會使用查詢優化器對查詢進行優化,根據客戶端請求的 query 語句,和數據庫中的一些統計信息,在一系列算法的基礎上進行分析,得出一個最優的策略,告訴後面的程序如何取得這個 query 語句的結果,即執行計劃。查詢優化器使用選取-投影-聯接策略生成執行計劃。 |
選取-投影-聯接:
用一個例子就能夠理解: select uid,name from user where gender = 1; 這個select 查詢先根據where 語句進行選取,而不是先將表所有查詢出來之後再進行gender過濾。 這個select查詢先根據uid和name進行屬性投影,而不是將屬性所有取出之後再進行過濾。 將這兩個查詢條件聯接起來生成最終查詢結果。 |
查詢緩存功能(Cache和Buffer):(建議關閉)
當執行sql的時候,sql第一次被執行,而後再次執行的時候若是相同的sql,能夠不進行解析,直接返回結果,提升查詢效率. 關閉查詢緩存:query_cache_type = 0 query_cache_size = 0 侷限性比較大,任何查詢結果有變動,都須要進行更新,對於mysql性能影響比較嚴重,整個更新過程的鎖顆粒度的比較高,還持有全局鎖,效率很低. 建議:是否使用查詢緩存,不用.(在mysql8.0裏沒了查詢緩存功能.) 問題:如何計算和提升查詢緩存命中率? |
第3層儲存引擎層(StorEngine Layer):
儲存引擎層功能:
存儲引擎,也稱爲表類型,真正的負責了MySQL中數據的存儲和提取,儲存引擎層由多種存儲引擎共同組成。它們負責存儲和獲取全部存儲在MySQL中的數據。就像Linux衆多的文件系統 同樣。每一個存儲引擎都有本身的優勢和缺陷。服務器是經過存儲引擎API來與它們交互的。存儲引擎不能解析SQL,互相之間也不能通訊。僅僅是簡單的響應服務器 的請求。存儲引擎不會互相通訊。不一樣的存儲引擎採用不一樣的技術(存儲機制、索引機制、鎖定機制)存儲數據。 MySQL的存儲引擎是插件式的,也就是說,用戶能夠隨時切換MySQL的存儲引擎:針對表或針對庫均可(經過SQL語句命令)。MySQL集合了多種引擎:MyISAM、InnoDB、BDB、Merge、Memory等,默認的是InnoDB。 |
儲存引擎層說明:
一、根據上層獲取數據的方法(執行計劃),將數據提取出來。 二、從新再交給SQL層。 三、是MYSQL數據庫的核心,關係到數據庫性能。 四、存儲引擎是基於表的,而不是數據庫。 |
常見的MySQL的存儲引擎及特色:
存儲引擎 特色 InnoDB 持事務安全。可是對比MyISAM引擎,寫的處效率會差些 MyISAM 支持事務,插速度般innodb快一些 Memory 數據存儲於內存之中 CSV 數據存儲爲CSV件格式,不進轉換 |
查看mysql儲存引擎:
mysql> show plugins; ---查看插件及其狀態 mysql> show engines; ---查看目前支持的儲存引擎 |
InnoDB和MyISAM區別:
InnoDB MyISAM 索引組織表 堆表 鎖 表鎖 物理結構不一樣,數據索引在起(.frm) 物理結構不一樣,數據索引分開(.MYD .MYI) 支持事務 不支持事務 支持外鍵 不支持外鍵 MVCC多版本控制 INNODB緩存索引和數據 MyISAM只緩存索引塊 |
說明:
經過對開關binlog前後的測試發現,其實MySIAM的插性能要好於INNODB,這和MySIAM不支持事務,鎖開銷也較有關。 可是MySiam的表鎖讓該引擎不能在併發下工做,由於會形成的鎖衝突。在線業務OLTP業務,強烈不建議使MySIAM的存儲引擎,併發效率很低。 |
建立表時指定儲存引擎:
create table test1 ( id int, name varchar(11) )engine=innodb; create table test2 ( id int, name varchar(11) )engine=myisam ; |
InnoDB的物理存儲結構:
test1.frm #表結構文件 test1.ibd #表數據文件(存儲數據和索引) |
MySIAM的物理存儲結構:
test2.frm #表結構文件 test2.MYD #表數據文件 test2.MYI #表索引文件 |
修改MyISAM表結構到InnoDB表:
alter table test2 engine = innodb; show create table test2\G; Create Table: CREATE TABLE `test2` ( `id` int(11) DEFAULT NULL, `name` varchar(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
注意: MySQL 的系統表, user 等不能轉化爲 InnoDB 格式,他們必須採用 MyISAM 格式!!