1. 程式人生 > 資料庫 >關於MySQL效能調優你必須瞭解的15個重要變數(小結)

關於MySQL效能調優你必須瞭解的15個重要變數(小結)

前言:

MYSQL 應該是最流行了 WEB 後端資料庫。雖然 NOSQL 最近越來越多的被提到,但是相信大部分架構師還是會選擇 MYSQL 來做資料儲存。本文作者總結梳理MySQL效能調優的15個重要變數,又不足需要補充的還望大佬指出。

1.DEFAULT_STORAGE_ENGINE

如果你已經在用MySQL 5.6或者5.7,並且你的資料表都是InnoDB,那麼表示你已經設定好了。如果沒有,確保把你的錶轉換為InnoDB並且設定default_storage_engine為InnoDB。

為什麼?簡而言之,因為InnoDB是MySQL(包括Percona Server和MariaDB)最好的儲存引擎 – 它支援事務,高併發,有著非常好的效能表現(當配置正確時)。這裡有詳細的版本介紹為什麼

2.INNODB_BUFFER_POOL_SIZE

這個是InnoDB最重要變數。實際上,如果你的主要儲存引擎是InnoDB,那麼對於你,這個變數對於MySQL是最重要的。

基本上,innodb_buffer_pool_size指定了MySQL應該分配給InnoDB緩衝池多少記憶體,InnoDB緩衝池用來儲存快取的資料,二級索引,髒資料(已經被更改但沒有重新整理到硬碟的資料)以及各種內部結構如自適應雜湊索引。

根據經驗,在一個獨立的MySQL伺服器應該分配給MySQL整個機器總記憶體的80%。如果你的MySQL執行在一個共享伺服器,或者你想知道InnoDB緩衝池大小是否正確設定,詳細請看這裡。

3.INNODB_LOG_FILE_SIZE

InnoDB重做日誌檔案的設定在MySQL社群也叫做事務日誌。直到MySQL 5.6.8事務日誌預設值innodb_log_file_size=5M是唯一最大的InnoDB效能殺手。從MySQL 5.6.8開始,預設值提升到48M,但對於許多稍繁忙的系統,還遠遠要低。

根據經驗,你應該設定的日誌大小能在你伺服器繁忙時能儲存1-2小時的寫入量。如果不想這麼麻煩,那麼設定1-2G的大小會讓你的效能有一個不錯的表現。這個變數也相當重要,更詳細的介紹請看這裡。

在進入下一個變數之前,讓我們來快速提及一下innodb_log_buffer_size。“快速提及”是因為它常常不好理解並且往往被過度關注了。事實上大多數情況下你只需要使用小的緩衝 – 在事務被提交併寫入到硬碟前足夠儲存你的小事務更改了。

當然,如果你有大量的大事務更改,那麼,更改比預設innodb日誌緩衝大小更大的值會對你的效能有一定的提高,但是你使用的是autocommit,或者你的事務更改小於幾k,那還是保持預設的值吧。

4.INNODB_FLUSH_LOG_AT_TRX_COMMIT

預設下,innodb_flush_log_at_trx_commit設定為1表示InnoDB在每次事務提交後立即重新整理同步資料到硬碟。如果你使用autocommit,那麼你的每一個INSERT,UPDATE或DELETE語句都是一個事務提交。

同步是一個昂貴的操作(特別是當你沒有寫回快取時),因為它涉及對硬碟的實際同步物理寫入。所以如果可能,並不建議使用預設值。

兩個可選的值是0和2:

* 0表示重新整理到硬碟,但不同步(提交事務時沒有實際的IO操作)

* 2表示不重新整理和不同步(也沒有實際的IO操作)

所以你如果設定它為0或2,則同步操作每秒執行一次。所以明顯的缺點是你可能會丟失上一秒的提交資料。具體來說,你的事務已經提交了,但伺服器馬上斷電了,那麼你的提交相當於沒有發生過。

顯示的,對於金融機構,如銀行,這是無法忍受的。不過對於大多數網站,可以設定為innodb_flush_log_at_trx_commit=0|2,即使伺服器最終崩潰也沒有什麼大問題。畢竟,僅僅在幾年前有許多網站還是用MyISAM,當崩潰時會丟失30s的資料(更不要提那令人抓狂的慢修復程序)。

那麼,0和2之間的實際區別是什麼?效能明顯的差異是可以忽略不計,因為重新整理到作業系統快取的操作是非常快的。所以很明顯應該設定為0,萬一MySQL崩潰(不是整個機器),你不會丟失任何資料,因為資料已經在OS快取,最終還是會同步到硬碟的。

5.SYNC_BINLOG

已經有大量的文件寫到sync_binlog,以及它和innodb_flush_log_at_trx_commit的關係,下面我們來簡單的介紹下:

a) 如果你的伺服器沒有設定從伺服器,而且你不做備份,那麼設定sync_binlog=0將對效能有好處。

b) 如果你有從伺服器並且做備份,但你不介意當主伺服器崩潰時在二進位制日誌丟失一些事件,那麼為了更好的效能還是設定為sync_binlog=0.

c) 如果你有從伺服器並且備份,你非常在意從伺服器的一致性,以及能及時恢復到一個時間點(通過使用最新的一致性備份和二進位制日誌將資料庫恢復到特定時間點的能力),那麼你應該設定innodb_flush_log_at_trx_commit=1,並且需要認真考慮使用sync_binlog=1。

問題是sync_binlog=1代價比較高 – 現在每個事務也要同步一次到硬碟。你可能會想為什麼不把兩次同步合併成一次,想法正確 – 新版本的MySQL(5.6和5.7,MariaDB和Percona Server)已經能合併提交,那麼在這種情況下sync_binlog=1的操作也不是這麼昂貴了,但在舊的mysql版本中仍然會對效能有很大影響。

6.INNODB_FLUSH_METHOD

將innodb_flush_method設定為O_DIRECT以避免雙重緩衝.唯一一種情況你不應該使用O_DIRECT是當你作業系統不支援時。但如果你執行的是Linux,使用O_DIRECT來啟用直接IO。

不用直接IO,雙重緩衝將會發生,因為所有的資料庫更改首先會寫入到OS快取然後才同步到硬碟 – 所以InnoDB緩衝池和OS快取會同時持有一份相同的資料。特別是如果你的緩衝池限制為總記憶體的50%,那意味著在寫密集的環境中你可能會浪費高達50%的記憶體。如果沒有限制為50%,伺服器可能由於OS快取的高壓力會使用到swap。

簡單地說,設定為innodb_flush_method=O_DIRECT。

7.INNODB_BUFFER_POOL_INSTANCES

MySQL 5.5引入了緩衝例項作為減小內部鎖爭用來提高MySQL吞吐量的手段。

在5.5版本這個對提升吞吐量幫助很小,然後在MySQL 5.6版本這個提升就非常大了,所以在MySQL5.5中你可能會保守地設定innodb_buffer_pool_instances=4,在MySQL 5.6和5.7中你可以設定為8-16個緩衝池例項。

你設定後觀察會覺得效能提高不大,但在大多數高負載情況下,它應該會有不錯的表現。

對了,不要指望這個設定能減少你單個查詢的響應時間。這個是在高併發負載的伺服器上才看得出區別。比如多個執行緒同時做許多事情。

8.INNODB_THREAD_CONCURRENCY

你可能會經常聽到應該設定innodb_thread_concurrency=0然後就不要管它了。不過這個只在低負載伺服器使用時才正確。然後,如果你的伺服器的CPU或者IO使用接受飽和,特別是偶爾出現峰值,這時候系統想在超載時能正常處理查詢,那麼強烈建議關注innodb_thread_concurrency。

InnoDB有一種方法來控制並行執行的執行緒數 – 我們稱為併發控制機制。大部分是由innodb_thread_concurrency值來控制的。如果設定為0,併發控制就關閉了,因此InnoDB會立即處理所有進來的請求(儘可能多的)。

在你有32CPU核心且只有4個請求時會沒什麼問題。不過想像下你只有4CPU核心和32個請求時 – 如果你讓32個請求同時處理,你這個自找麻煩。因為這些32個請求只有4 CPU核心,顯然地會比平常慢至少8倍(實際上是大於8倍),而然這些請求每個都有自己的外部和內部鎖,這有很大可能堆積請求。

下面介紹如何更改這個變數,在mysql命令列提示符執行:

SET global innodb_thread_concurrency=X;

對於大多數工作負載和伺服器,設定為8是一個好開端,然後你可以根據伺服器達到了這個限制而資源使用率利用不足時逐漸增加。可以通過show engine innodb status\G來檢視目前查詢處理情況,查詢類似如下行:

22 queries inside InnoDB,104 queries in queue

9.SKIP_NAME_RESOLVE

這一項不得不提及,因為仍然有很多人沒有新增這一項。你應該新增skip_name_resolve來避免連線時DNS解析。

大多數情況下你更改這個會沒有什麼感覺,因為大多數情況下DNS伺服器解析會非常快。不過當DNS伺服器失敗時,它會出現在你伺服器上出現“unauthenticated connections” ,而就是為什麼所有的請求都突然開始慢下來了。

所以不要等到這種事情發生才更改。現在新增這個變數並且避免基於主機名的授權。

10.INNODB_IO_CAPACITY,INNODB_IO_CAPACITY_MAX

* innodb_io_capacity:用來當重新整理髒資料時,控制MySQL每秒執行的寫IO量。

* innodb_io_capacity_max: 在壓力下,控制當重新整理髒資料時MySQL每秒執行的寫IO量

首先,這與讀取無關 – SELECT查詢執行的操作。對於讀操作,MySQL會盡最大可能處理並返回結果。至於寫操作,MySQL在後臺會迴圈重新整理,在每一個迴圈會檢查有多少資料需要重新整理,並且不會用超過innodb_io_capacity指定的數來做重新整理操作。這也包括更改緩衝區合併(在它們重新整理到磁碟之前,更改緩衝區是輔助髒頁儲存的關鍵)。

第二,我需要解釋一下什麼叫“在壓力下”,MySQL中稱為”緊急情況”,是當MySQL在後臺重新整理時,它需要重新整理一些資料為了讓新的寫操作進來。然後,MySQL會用到innodb_io_capacity_max。

那麼,應該設定innodb_io_capacity和innodb_io_capacity_max為什麼呢?

最好的方法是測量你的儲存設定的隨機寫吞吐量,然後給innodb_io_capacity_max設定為你的裝置能達到的最大IOPS。innodb_io_capacity就設定為它的50-75%,特別是你的系統主要是寫操作時。

通常你可以預測你的系統的IOPS是多少。例如由8 15k硬碟組成的RAID10能做大約每秒1000隨機寫操作,所以你可以設定innodb_io_capacity=600和innodb_io_capacity_max=1000。許多廉價企業SSD可以做4,000-10,000 IOPS等。

這個值設定得不完美問題不大。但是,要注意預設的200和400會限制你的寫吞吐量,因此你可能偶爾會捕捉到重新整理程序。如果出現這種情況,可能是已經達到你硬碟的寫IO吞吐量,或者這個值設定得太小限制了吞吐量。

11.INNODB_STATS_ON_METADATA

如果你跑的是MySQL 5.6或5.7,你不需要更改innodb_stats_on_metadata的預設值,因為它已經設定正確了。

不過在MySQL 5.5或5.1,強烈建議關閉這個變數 – 如果是開啟,像命令show table status會立即查詢INFORMATION_SCHEMA而不是等幾秒再執行,這會使用到額外的IO操作。

從5.1.32版本開始,這個是動態變數,意味著你不需要重啟MySQL伺服器來關閉它。

12.INNODB_BUFFER_POOL_DUMP_AT_SHUTDOWN & INNODB_BUFFER_POOL_LOAD_AT_STARTUP

innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup這兩個變數與效能無關,不過如果你偶爾重啟mysql伺服器(如生效配置),那麼就有關。當兩個都啟用時,MySQL緩衝池的內容(更具體地說,是快取頁)在停止MySQL時儲存到一個檔案。當你下次啟動MySQL時,它會在後臺啟動一個執行緒來載入緩衝池的內容以提高預熱速度到3-5倍。

兩件事:

第一,它實際上沒有在關閉時複製緩衝池內容到檔案,僅僅是複製表空間ID和頁面ID – 足夠的資訊來定位硬碟上的頁面了。然後它就能以大量的順序讀非常快速的載入那些頁面,而不是需要成千上萬的小隨機讀。

第二,啟動時是在後臺載入內容,因為MySQL不需要等到緩衝池內容載入完成再開始接受請求(所以看起來不會有什麼影響)。

從MySQL 5.7.7開始,預設只有25%的緩衝池頁面在mysql關閉時儲存到檔案,但是你可以控制這個值 – 使用innodb_buffer_pool_dump_pct,建議75-100。

這個特性從MySQL 5.6才開始支援。

13.INNODB_ADAPTIVE_HASH_INDEX_PARTS

如果你執行著一個大量SELECT查詢的MySQL伺服器(並且已經儘可能優化),那麼自適應雜湊索引將下你的下一個瓶頸。自適應雜湊索引是InnoDB內部維護的動態索引,可以提高最常用的查詢模式的效能。這個特性可以重啟伺服器關閉,不過預設下在mysql的所有版本開啟。

這個技術非常複雜,在大多數情況下它會對大多數型別的查詢直到加速的作用。不過,當你有太多的查詢往資料庫,在某一個點上它會花過多的時間等待AHI鎖和閂鎖。

如果你的是MySQL 5.7,沒有這個問題 – innodb_adaptive_hash_index_parts預設設定為8,所以自適應雜湊索引被切割為8個分割槽,因為不存在全域性互斥。

不過在mysql 5.7前的版本,沒有AHI分割槽數量的控制。換句話說,有一個全域性互斥鎖來保護AHI,可能導致你的select查詢經常撞牆。

所以如果你執行的是5.1或5.6,並且有大量的select查詢,最簡單的方案就是切換成同一版本的Percona Server來啟用AHI分割槽。

14.QUERY_CACHE_TYPE

如果人認為查詢快取效果很好,肯定應該使用它。好吧,有時候是有用的。不過這個只在你在低負載時有用,特別是在低負載下大多數是讀取,小量寫或者沒有。

如果是那樣的情況,設定query_cache_type=ON和query_cache_size=256M就好了。不過記住不能把256M設定更高的值了,否則會由於查詢快取失效時,導致引起嚴重的伺服器停頓。

如果你的MySQL伺服器高負載動作,建議設定query_cache_size=0和query_cache_type=OFF,並重啟伺服器生效。那樣Mysql就會停止在所有的查詢使用查詢快取互斥鎖。

15.TABLE_OPEN_CACHE_INSTANCES

從MySQL 5.6.6開始,表快取能分割到多個分割槽。

表快取用來存放目前已開啟表的列表,當每一個表開啟或關閉互斥體就被鎖定 – 即使這是一個隱式臨時表。使用多個分割槽絕對減少了潛在的爭用。

從MySQL 5.7.8開始,table_open_cache_instances=16是預設的配置。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。