MySQL 性能優化

在平時被問及最多的問題就是關於 MySQL 數據庫性能優化方面的問題,因此最近打算寫一個MySQL數據庫性能優化方面的系列文章,但願對初中級 MySQL DBA 以及其餘對 MySQL 性能優化感興趣的朋友們有所幫助。mysql

這是 MySQL數據庫性能優化專題 系列的第一篇文章:MySQL 數據庫性能優化之緩存參數優化linux

數據庫屬於 IO 密集型的應用程序,其主要職責就是數據的管理及存儲工做。而咱們知道,從內存中讀取一個數據庫的時間是微秒級別,而從一塊普通硬盤上讀取一個IO是在毫秒級別,兩者相差3個數量級。因此,要優化數據庫,首先第一步須要優化的就是 IO,儘量將磁盤IO轉化爲內存IO。本文先從 MySQL 數據庫IO相關參數(緩存參數)的角度來看看能夠經過哪些參數進行IO優化算法

Query cache 做用於整個 MySQL Instance,主要用來緩存 MySQL 中的 ResultSet,也就是一條SQL語句執行的結果集,因此僅僅只能針對select語句。當咱們打開了 Query Cache 功能,MySQL在接受到一條select語句的請求後,若是該語句知足Query Cache的要求(未顯式說明不容許使用Query Cache,或者已經顯式申明須要使用Query Cache),MySQL 會直接根據預先設定好的HASH算法將接受到的select語句以字符串方式進行hash,而後到Query Cache 中直接查找是否已經緩存。也就是說,若是已經在緩存中,該select請求就會直接將數據返回,從而省略了後面全部的步驟(如 SQL語句的解析,優化器優化以及向存儲引擎請求數據等),極大的提升性能。sql

固然,Query Cache 也有一個致命的缺陷,那就是當某個表的數據有任何任何變化,都會致使全部引用了該表的select語句在Query Cache 中的緩存數據失效。因此,當咱們的數據變化很是頻繁的狀況下,使用Query Cache 可能會得不償失。數據庫

Query Cache的使用須要多個參數配合,其中最爲關鍵的是 query_cache_size 和 query_cache_type ,前者設置用於緩存 ResultSet 的內存大小,後者設置在何場景下使用 Query Cache。在以往的經驗來看,若是不是用來緩存基本不變的數據的MySQL數據庫,query_cache_size 通常 256MB 是一個比較合適的大小。固然,這能夠經過計算Query Cache的命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))來進行調整。 query_cache_type能夠設置爲0(OFF),1(ON)或者2(DEMOND),分別表示徹底不使用query cache,除顯式要求不使用query cache(使用sql_no_cache)以外的全部的select都使用query cache,只有顯示要求才使用query cache(使用sql_cache)。緩存

Binlog Cache 用於在打開了二進制日誌(binlog)記錄功能的環境,是 MySQL 用來提升binlog的記錄效率而設計的一個用於短期內臨時緩存binlog數據的內存區域。性能優化

通常來講,若是咱們的數據庫中沒有什麼大事務,寫入也不是特別頻繁,2MB~4MB是一個合適的選擇。可是若是咱們的數據庫大事務較多,寫入量比較大,可與適當調高binlog_cache_size。同時,咱們能夠經過binlog_cache_use 以及 binlog_cache_disk_use來分析設置的binlog_cache_size是否足夠,是否有大量的binlog_cache因爲內存大小不夠而使用臨時文件(binlog_cache_disk_use)來緩存了。數據結構

Key Buffer 多是你們最爲熟悉的一個 MySQL 緩存參數了,尤爲是在 MySQL 沒有更換默認存儲引擎的時候,不少朋友可能會發現,默認的 MySQL 配置文件中設置最大的一個內存參數就是這個參數了。key_buffer_size 參數用來設置用於緩存 MyISAM存儲引擎中索引文件的內存區域大小。若是咱們有足夠的內存,這個緩存區域最好是可以存放下咱們全部的 MyISAM 引擎表的全部索引,以儘量提升性能。架構

此外,當咱們在使用MyISAM 存儲的時候有一個及其重要的點須要注意,因爲 MyISAM 引擎的特性限制了他僅僅只會緩存索引塊到內存中,而不會緩存表數據庫塊。因此,咱們的 SQL 必定要儘量讓過濾條件都在索引中,以便讓緩存幫助咱們提升查詢效率。性能

和key_buffer_size同樣,這個參數一樣也僅做用於使用 MyISAM存儲引擎,用來緩存批量插入數據的時候臨時緩存寫入數據。當咱們使用以下幾種數據寫入語句的時候,會使用這個內存區域來緩存批量結構的數據以幫助批量寫入數據文件:

insert … select …
insert … values (…) ,(…),(…)…
load data infile… into… (非空表)

當咱們使用InnoDB存儲引擎的時候,innodb_buffer_pool_size 參數多是影響咱們性能的最爲關鍵的一個參數了,他用來設置用於緩存 InnoDB 索引及數據塊的內存區域大小,相似於 MyISAM 存儲引擎的 key_buffer_size 參數,固然,可能更像是 Oracle 的 db_cache_size。簡單來講,當咱們操做一個 InnoDB 表的時候,返回的全部數據或者去數據過程當中用到的任何一個索引塊,都會在這個內存區域中走一遭。

和key_buffer_size 對於 MyISAM 引擎同樣,innodb_buffer_pool_size 設置了 InnoDB 存儲引擎需求最大的一塊內存區域的大小,直接關係到 InnoDB存儲引擎的性能,因此若是咱們有足夠的內存,儘可將該參數設置到足夠打,將盡量多的 InnoDB 的索引及數據都放入到該緩存區域中,直至所有。

咱們能夠經過 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 計算緩存命中率,並根據命中率來調整 innodb_buffer_pool_size 參數大小進行優化。

這個參數咱們平時調整的可能不是太多,不少人都使用了默認值,可能不少人都不是太熟悉這個參數的做用。 innodb_additional_mem_pool_size 設置了InnoDB存儲引擎用來存放數據字典信息以及一些內部數據結構的內存空間大小,因此當咱們一個MySQL Instance中的數據庫對象很是多的時候,是須要適當調整該參數的大小以確保全部數據都能存放在內存中提升訪問效率的。

這個參數大小是否足夠仍是比較容易知道的,由於當太小的時候,MySQL 會記錄 Warning 信息到數據庫的 error log 中,這時候你就知道該調整這個參數大小了。

這是 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 Buffer Pool 中能夠不用寫入數據文件中的Dirty Page 的比例(已經被修但尚未從內存中寫入到數據文件的髒數據)。這個比例值越大,從內存到磁盤的寫入操做就會相對減小,因此可以必定程度下減小寫入操做的磁盤IO。

可是,若是這個比例值過大,當數據庫 Crash 以後重啓的時間可能就會很長,由於會有大量的事務數據須要從日誌文件恢復出來寫入數據文件中。同時,過大的比例值同時可能也會形成在達到比例設定上限後的 flush 操做「過猛」而致使性能波動很大。

  • query_cache_size/query_cache_type (global)
  • binlog_cache_size (global)
  • key_buffer_size (global)
  • bulk_insert_buffer_size (thread)
  • innodb_buffer_pool_size(global)
  • innodb_additional_mem_pool_size(global)
  • innodb_log_buffer_size (global)
  • innodb_max_dirty_pages_pct (global)

上面這幾個參數是 MySQL 中爲了減小磁盤物理IO而設計的主要參數,對 MySQL 的性能起到了相當重要的做用。

—EOF—

按照 mcsrainbow 朋友的要求,這裏列一下根據以往經驗獲得的相關參數的建議值:

  • query_cache_type : 若是所有使用innodb存儲引擎,建議爲0,若是使用MyISAM 存儲引擎,建議爲2,同時在SQL語句中顯式控制是不是喲你gquery cache
  • query_cache_size: 根據 命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))進行調整,通常不建議太大,256MB可能已經差很少了,大型的配置型靜態數據可適當調大
  • binlog_cache_size: 通常環境2MB~4MB是一個合適的選擇,事務較大且寫入頻繁的數據庫環境能夠適當調大,但不建議超過32MB
  • key_buffer_size: 若是不使用MyISAM存儲引擎,16MB足以,用來緩存一些系統表信息等。若是使用 MyISAM存儲引擎,在內存容許的狀況下,儘量將全部索引放入內存,簡單來講就是「越大越好」
  • bulk_insert_buffer_size: 若是常常性的須要使用批量插入的特殊語句(上面有說明)來插入數據,能夠適當調大該參數至16MB~32MB,不建議繼續增大,某人8MB
  • innodb_buffer_pool_size: 若是不使用InnoDB存儲引擎,能夠不用調整這個參數,若是須要使用,在內存容許的狀況下,儘量將全部的InnoDB數據文件存放如內存中,一樣將但來講也是「越大越好」
  • innodb_additional_mem_pool_size: 通常的數據庫建議調整到8MB~16MB,若是表特別多,能夠調整到32MB,能夠根據error log中的信息判斷是否須要增大
  • innodb_log_buffer_size: 默認是1MB,系的如頻繁的系統可適當增大至4MB~8MB。固然如上面介紹所說,這個參數實際上還和另外的flush參數相關。通常來講不建議超過32MB
  • innodb_max_dirty_pages_pct: 根據以往的經驗,重啓恢復的數據若是要超過1GB的話,啓動速度會比較慢,幾乎難以接受,因此建議不大於 1GB/innodb_buffer_pool_size(GB)*100 這個值。固然,若是你可以忍受啓動時間比較長,並且但願儘可能減小內存至磁盤的flush,能夠將這個值調整到90,但不建議超過90

注:以上取值範圍僅僅只是個人根據以往遇到的數據庫場景所獲得的一些優化經驗值,並不必定適用於全部場景,因此在實際優化過程當中還須要你們本身不斷的調整分析,也歡迎你們隨時經過 Mail 與我聯繫溝通交流優化或者是架構方面的技術,一塊兒探討相互學習。

相關文章
相關標籤/搜索