mysql 內存使用

對於任何一個數據庫管理系統來講,內存的分配使用絕對能夠算的上是其核心之一了,因此不少但願更爲深刻了解某數據庫管理系統的人,都會但願一窺究竟,我也不例外。mysql

從內存的使用方式MySQL 數據庫的內存使用主要分爲如下兩類算法


線程獨享內存
全局共享內存sql

線程獨享內存數據庫

在 MySQL 中,線程獨享內存主要用於各客戶端鏈接線程存儲各類操做的獨享數據,如線程棧信息,分組排序操做,數據讀寫緩衝,結果集暫存等等,並且大多數能夠經過相關參數來控制內存的使用量。緩存

線程棧信息使用內存(thread_stack):主要用來存放每個線程自身的標識信息,如線程id,線程運行時基本信息等等,咱們能夠經過 thread_stack 參數來設置爲每個線程棧分配多大的內存。網絡

排序使用內存(sort_buffer_size):MySQL用此內存區域進行排序操做(filesort),完成客戶端的排序請求。當咱們設置的排序區緩存大小沒法知足排序實際所需內存的時候,MySQL會將數據寫入磁盤文件來完成排序。因爲磁盤和內存的讀寫性能徹底不在一個數量級,因此sort_buffer_size參數對排序操做的性能影響絕對不可小視。數據結構

Join操做使用內存(join_buffer_size):應用程序常常會出現一些兩表(或多表)Join的操做需求,MySQL在完成某些 Join 需求的時候(all/indexjoin),爲了減小參與Join的「被驅動表」的讀取次數以提升性能,須要使用到 Join Buffer 來協助完成 Join操做。當 Join Buffer 過小,MySQL 不會將該 Buffer 存入磁盤文件,而是先將Join Buffer中的結果集與須要 Join的表進行 Join 操做,而後清空 Join Buffer 中的數據,繼續將剩餘的結果集寫入此 Buffer中,如此往復。這勢必會形成被驅動表須要被屢次讀取,成倍增長 IO 訪問,下降效率。ide

順序讀取數據緩衝區使用內存(read_buffer_size):這部份內存主要用於當須要順序讀取數據的時候,如無發使用索引的狀況下的全表掃描,全索引掃描等。在這種時候,MySQL按照數據的存儲順序依次讀取數據塊,每次讀取的數據快首先會暫存在read_buffer_size中,當 buffer空間被寫滿或者所有數據讀取結束後,再將buffer中的數據返回給上層調用者,以提升效率。性能

隨機讀取數據緩衝區使用內存(read_rnd_buffer_size):和順序讀取相對應,當MySQL進行非順序讀取(隨機讀取)數據塊的時候,會利用這個緩衝區暫存讀取的數據。如根據索引信息讀取表數據,根據排序後的結果集與表進行Join等等。總的來講,就是當數據塊的讀取須要知足必定的順序的狀況下,MySQL 就須要產生隨機讀取,進而使用到 read_rnd_buffer_size參數所設置的內存緩衝區。ui

鏈接信息及返回客戶端前結果集暫存使用內存(net_buffer_size):這部分用來存放客戶端鏈接線程的鏈接信息和返回客戶端的結果集。當 MySQL 開始產生能夠返回的結果集,會在經過網絡返回給客戶端請求線程以前,會先暫存在經過net_buffer_size所設置的緩衝區中,等知足必定大小的時候纔開始向客戶端發送,以提升網絡傳輸效率。不過,net_buffer_size參數所設置的僅僅只是該緩存區的初始化大小,MySQL 會根據實際須要自行申請更多的內存以知足需求,但最大不會超過max_allowed_packet 參數大小。

批量插入暫存使用內存(bulk_insert_buffer_size):當咱們使用如 insert …values(…),(…),(…)… 的方式進行批量插入的時候,MySQL會先將提交的數據放如一個緩存空間中,當該緩存空間被寫滿或者提交完全部數據以後,MySQL纔會一次性將該緩存空間中的數據寫入數據庫並清空緩存。此外,當咱們進行 LOAD DATA INFILE 操做來將文本文件中的數據 Load進數據庫的時候,一樣會使用到此緩衝區。

臨時表使用內存(tmp_table_size):當咱們進行一些特殊操做如須要使用臨時表才能完成的Order By,Group By 等等,MySQL 可能須要使用到臨時表。當咱們的臨時表較小(小於 tmp_table_size參數所設置的大小)的時候,MySQL 會將臨時表建立成內存臨時表,只有當 tmp_table_size所設置的大小沒法裝下整個臨時表的時候,MySQL 纔會將該表建立成 MyISAM 存儲引擎的表存放在磁盤上。不過,當另外一個系統參數max_heap_table_size 的大小還小於 tmp_table_size 的時候,MySQL 將使用max_heap_table_size 參數所設置大小做爲最大的內存臨時表大小,而忽略 tmp_table_size 所設置的值。並且tmp_table_size 參數從 MySQL 5.1.2 纔開始有,以前一直使用 max_heap_table_size。

上面所列舉的 MySQL 線程獨享內存僅僅只是全部線程獨享內存中的部分,並非所有,選擇的原則是可能對 MySQL 的性能產生較大的影響,且能夠經過系統參數進行調節。

因爲以上內存都是線程獨享,極端狀況下的內存整體使用量將是全部鏈接線程的總倍數。因此各位朋友在設置過程當中必定要謹慎,切不可爲了提高性能就盲目的增大各參數值,避免由於內存不夠而產生 Out Of Memory 異常或者是嚴重的 Swap 交換反而下降總體性能。

全局共享內存

全局共享內主要是 MySQLInstance(mysqld進程)以及底層存儲引擎用來暫存各類全局運算及可共享的暫存信息,如存儲查詢緩存的 QueryCache,緩存鏈接線程的 Thread Cache,緩存表文件句柄信息的 Table Cache,緩存二進制日誌的 BinLogBuffer, 緩存 MyISAM 存儲引擎索引鍵的 Key Buffer以及存儲 InnoDB 數據和索引的 InnoDB BufferPool 等等。下面針對 MySQL 主要的共享內存進行一個簡單的分析。

查詢緩存(Query Cache):查詢緩存是 MySQL 比較獨特的一個緩存區域,用來緩存特定Query 的結果集(Result Set)信息,且共享給全部客戶端。經過對 Query 語句進行特定的 Hash 計算以後與結果集對應存放在Query Cache 中,以提升徹底相同的 Query 語句的相應速度。當咱們打開 MySQL 的 Query Cache 以後,MySQL接收到每個 SELECT 類型的 Query 以後都會首先經過固定的 Hash 算法獲得該 Query 的 Hash 值,而後到 QueryCache 中查找是否有對應的 Query Cache。若是有,則直接將 Cache的結果集返回給客戶端。若是沒有,再進行後續操做,獲得對應的結果集以後將該結果集緩存到 Query Cache中,再返回給客戶端。當任何一個表的數據發生任何變化以後,與該表相關的全部 Query Cache 所有會失效,因此 Query Cache對變動比較頻繁的表並非很是適用,但對那些變動較少的表是很是合適的,能夠極大程度的提升查詢效率,如那些靜態資源表,配置表等等。爲了儘量高效的利用 Query Cache,MySQL 針對 Query Cache 設計了多個 query_cache_type 值和兩個 QueryHint:SQL_CACHE 和 SQL_NO_CACHE。當 query_cache_type 設置爲0(或者 OFF)的時候不使用Query Cache,當設置爲1(或者 ON)的時候,當且僅當 Query 中使用了 SQL_NO_CACHE 的時候 MySQL 會忽略Query Cache,當 query_cache_type 設置爲2(或者DEMAND)的時候,當且僅當Query 中使用了SQL_CACHE 提示以後,MySQL 纔會針對該 Query 使用 Query Cache。能夠經過 query_cache_size來設置可使用的最大內存空間。

鏈接線程緩存(Thread Cache):鏈接線程是 MySQL爲了提升建立鏈接線程的效率,將部分空閒的鏈接線程保持在一個緩存區以備新進鏈接請求的時候使用,這尤爲對那些使用短鏈接的應用程序來講能夠極大的提升建立鏈接的效率。當咱們經過 thread_cache_size設置了鏈接線程緩存池能夠緩存的鏈接線程的大小以後,能夠經過(Connections - Threads_created) /Connections * 100% 計算出鏈接線程緩存的命中率。注意,這裏設置的是能夠緩存的鏈接線程的數目,而不是內存空間的大小。

表緩存(Table Cache):表緩存區主要用來緩存表文件的文件句柄信息,在MySQL5.1.3以前的版本經過 table_cache 參數設置,但從MySQL5.1.3開始改成 table_open_cache來設置其大小。當咱們的客戶端程序提交 Query 給 MySQL 的時候,MySQL 須要對 Query所涉及到的每個表都取得一個表文件句柄信息,若是沒有 Table Cache,那麼 MySQL就不得不頻繁的進行打開關閉文件操做,無疑會對系統性能產生必定的影響,Table Cache 正是爲了解決這一問題而產生的。在有了 TableCache 以後,MySQL 每次須要獲取某個表文件的句柄信息的時候,首先會到 Table Cache中查找是否存在空閒狀態的表文件句柄。若是有,則取出直接使用,沒有的話就只能進行打開文件操做得到文件句柄信息。在使用完以後,MySQL會將該文件句柄信息再放回 Table Cache池中,以供其餘線程使用。注意,這裏設置的是能夠緩存的表文件句柄信息的數目,而不是內存空間的大小。

表定義信息緩存(Table definition Cache):表定義信息緩存是從MySQL5.1.3 版本纔開始引入的一個新的緩存區,用來存放表定義信息。當咱們的 MySQL中使用了較多的表的時候,此緩存無疑會提升對錶定義信息的訪問效率。MySQL 提供了 table_definition_cache參數給咱們設置能夠緩存的表的數量。在 MySQL5.1.25 以前的版本中,默認值爲128,從 MySQL5.1.25版本開始,則將默認值調整爲 256 了,最大設置值爲524288。注意,這裏設置的是能夠緩存的表定義信息的數目,而不是內存空間的大小。

二進制日誌緩衝區(Binlog Buffer):二進制日誌緩衝區主要用來緩存因爲各類數據變動操作所產生的Binary Log 信息。爲了提升系統的性能,MySQL 並非每次都是將二進制日誌直接寫入 Log File,而是先將信息寫入Binlog Buffer 中,當知足某些特定的條件(如 sync_binlog參數設置)以後再一次寫入 Log File 中。咱們能夠經過binlog_cache_size 來設置其可使用的內存大小,同時經過 max_binlog_cache_size限制其最大大小(當單個事務過大的時候 MySQL 會申請更多的內存)。當所需內存大於 max_binlog_cache_size參數設置的時候,MySQL 會報錯:「Multi-statement transaction required more than‘max_binlog_cache_size’ bytes of storage」。

MyISAM索引緩存(Key Buffer):MyISAM 索引緩存將 MyISAM 表的索引信息緩存在內存中,以提升其訪問性能。這個緩存能夠說是影響 MyISAM 存儲引擎性能的最重要因素之一了,經過 key_buffere_size 設置可使用的最大內存空間。

InnoDB 日誌緩衝區(InnoDB Log Buffer):這是 InnoDB存儲引擎的事務日誌所使用的緩衝區。相似於 Binlog Buffer,InnoDB 在寫事務日誌的時候,爲了提升性能,也是先將信息寫入Innofb Log Buffer 中,當知足 innodb_flush_log_trx_commit參數所設置的相應條件(或者日誌緩衝區寫滿)以後,纔會將日誌寫到文件(或者同步到磁盤)中。能夠經過 innodb_log_buffer_size參數設置其可使用的最大內存空間。
注:innodb_flush_log_trx_commit 參數對 InnoDB Log 的寫入性能有很是關鍵的影響。該參數能夠設置爲0,1,2,解釋以下:


0:log buffer中的數據將以每秒一次的頻率寫入到log file中,且同時會進行文件系統到磁盤的同步操做,可是每一個事務的commit並不會觸發任何log buffer 到log file的刷新或者文件系統到磁盤的刷新操做;
1:在每次事務提交的時候將log buffer 中的數據都會寫入到log file,同時也會觸發文件系統到磁盤的同步;
2:事務提交會觸發log buffer 到log file的刷新,但並不會觸發磁盤文件系統到磁盤的同步。此外,每秒會有一次文件系統到磁盤同步操做。
此外,MySQL文檔中還提到,這幾種設置中的每秒同步一次的機制,可能並不會徹底確保很是準確的每秒就必定會發生同步,還取決於進程調度的問題。實際上,InnoDB 可否真正知足此參數所設置值表明的意義正常 Recovery 仍是受到了不一樣 OS下文件系統以及磁盤自己的限制,可能有些時候在並無真正完成磁盤同步的狀況下也會告訴 mysqld 已經完成了磁盤同步。

InnoDB 數據和索引緩存(InnoDB Buffer Pool):InnoDB BufferPool 對 InnoDB 存儲引擎的做用相似於 Key Buffer Cache 對 MyISAM 存儲引擎的影響,主要的不一樣在於InnoDB Buffer Pool 不只僅緩存索引數據,還會緩存表的數據,並且徹底按照數據文件中的數據快結構信息來緩存,這一點和Oracle SGA 中的 database buffer cache 很是相似。因此,InnoDB Buffer Pool 對 InnoDB存儲引擎的性能影響之大就可想而知了。能夠經過 (Innodb_buffer_pool_read_requests -Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100%計算獲得 InnoDB Buffer Pool 的命中率。

InnoDB 字典信息緩存(InnoDB Additional Memory Pool):InnoDB字典信息緩存主要用來存放 InnoDB 存儲引擎的字典信息以及一些 internal 的共享數據結構信息。因此其大小也與系統中所使用的InnoDB 存儲引擎表的數量有較大關係。不過,若是咱們經過 innodb_additional_mem_pool_size參數所設置的內存大小不夠,InnoDB 會自動申請更多的內存,並在 MySQL 的 Error Log 中記錄警告信息。

這裏所列舉的各類共享內存,是我我的認爲對 MySQL 性能有較大影響的集中主要的共享內存。實際上,除了這些共享內存以外,MySQL 還存在不少其餘的共享內存信息,如當同時請求鏈接過多的時候用來存放鏈接請求信息的back_log隊列等。 以上內容可能存在分析不妥之處,歡迎各位朋友拍磚,一塊兒交流。

相關文章
相關標籤/搜索