(轉)例項分析:MySQL優化經驗

神馬和浮雲發表於2013-07-10

  【IT專家網獨家】同時線上訪問量繼續增大,對於1G記憶體的伺服器明顯感覺到吃力,嚴重時甚至每天都會當機,或者時不時的伺服器卡一下,這個問題曾經困擾了我半個多月。MySQL使用是很具伸縮性的演算法,因此你通常能用很少的記憶體執行或給MySQL更多的記憶體以得到更好的效能。

  安裝好mysql後,配製檔案應該在/usr/local/mysql/share/mysql目錄中,配製檔案有幾個,有my- huge.cnf、my-medium.cnf、my-large.cnf、my-small.cnf,不同流量的網站和不同配製的伺服器環境,當然需要有不同的配製檔案了。

  一般的情況下,my-medium.cnf這個配製檔案就能滿足我們的大多需要;一般我們會把配置檔案拷貝到/etc/my.cnf,只需要修改這個配置檔案就可以了,使用mysqladmin variables extended-status –u root –p 可以看到目前的引數,有3個配置引數是最重要的,即key_buffer_size,query_cache_size,table_cache。

  key_buffer_size只對MyISAM表起作用,key_buffer_size指定索引緩衝區的大小,它決定索引處理的速度,尤其是索引讀的速度。一般我們設為16M,實際上稍微大一點的站點 這個數字是遠遠不夠的,通過檢查狀態值Key_read_requests和Key_reads,可以知道key_buffer_size設定是否合理。比例key_reads / key_read_requests應該儘可能的低,至少是1:100,1:1000更好(上述狀態值可以使用SHOW STATUS LIKE ‘key_read%’獲得)。 或者如果你裝了phpmyadmin 可以通過伺服器執行狀態看到,筆者推薦用phpmyadmin管理mysql,以下的狀態值都是本人通過phpmyadmin獲得的例項分析:

  這個伺服器已經執行了20天

  •   key_buffer_size – 128M
  •   key_read_requests – 650759289
  •   key_reads - 79112

  比例接近1:8000 健康狀況非常好

  另外一個估計key_buffer_size的辦法,把你網站資料庫的每個表的索引所佔空間大小加起來看看。以此伺服器為例:比較大的幾個表索引加起來大概125M,這個數字會隨著表變大而變大。

  從4.0.1開始,MySQL提供了查詢緩衝機制。使用查詢緩衝,MySQL將SELECT語句和查詢結果存放在緩衝區中,今後對於同樣的SELECT語句(區分大小寫),將直接從緩衝區中讀取結果。根據MySQL使用者手冊,使用查詢緩衝最多可以達到238%的效率。

  通過調節以下幾個引數可以知道query_cache_size設定得是否合理

  •   Qcache inserts
  •   Qcache hits
  •   Qcache lowmem prunes
  •   Qcache free blocks
  •   Qcache total blocks

  Qcache_lowmem_prunes的值非常大,則表明經常出現緩衝不夠的情況,同時Qcache_hits的值非常大,則表明查詢緩衝使用非常頻繁,此時需要增加緩衝大小Qcache_hits的值不大,則表明你的查詢重複率很低,這種情況下使用查詢緩衝反而會影響效率,那麼可以考慮不用查詢緩衝。此外,在SELECT語句中加入SQL_NO_CACHE可以明確表示不使用查詢緩衝。

  Qcache_free_blocks,如果該值非常大,則表明緩衝區中碎片很多query_cache_type指定是否使用查詢緩衝。

  我設定:

  query_cache_size = 32M

  query_cache_type= 1

  得到如下狀態值:

  Qcache queries in cache 12737 表明目前快取的條數

  Qcache inserts 20649006

  Qcache hits 79060095  看來重複查詢率還挺高的

  Qcache lowmem prunes 617913 有這麼多次出現快取過低的情況

  Qcache not cached 189896

  Qcache free memory 18573912  目前剩餘快取空間

  Qcache free blocks 5328 這個數字似乎有點大 碎片不少

  Qcache total blocks 30953

  如果記憶體允許32M應該要往上加點

  table_cache指定表快取記憶體的大小。每當MySQL訪問一個表時,如果在表緩衝區中還有空間,該表就被開啟並放入其中,這樣可以更快地訪問表內容。通過檢查峰值時間的狀態值Open_tables和Opened_tables,可以決定是否需要增加table_cache的值。如果你發現open_tables等於table_cache,並且opened_tables在不斷增長,那麼你就需要增加table_cache的值了(上述狀態值可以使用SHOW STATUS LIKE ‘Open%tables’獲得)。注意,不能盲目地把table_cache設定成很大的值。如果設定得太高,可能會造成檔案描述符不足,從而造成效能不穩定或者連線失敗。

  對於有1G記憶體的機器,推薦值是128-256。

  設定table_cache = 256

  得到以下狀態:

  Open tables 256

  Opened tables 9046

  雖然open_tables已經等於table_cache,但是相對於伺服器執行時間來說,已經執行了20天,opened_tables的值也非常低。因此,增加table_cache的值應該用處不大。如果執行了6個小時就出現上述值 那就要考慮增大table_cache。

  如果你不需要記錄2進位制log 就把這個功能關掉,注意關掉以後就不能恢復出問題前的資料了,需要您手動備份,二進位制日誌包含所有更新資料的語句,其目的是在恢復資料庫時用它來把資料儘可能恢復到最後的狀態。另外,如果做同步複製( Replication )的話,也需要使用二進位制日誌傳送修改情況。

  log_bin指定日誌檔案,如果不提供檔名,MySQL將自己產生預設檔名。MySQL會在檔名後面自動新增數字引,每次啟動服務時,都會重新生成一個新的二進位制檔案。此外,使用log-bin-index可以指定索引檔案;使用binlog-do-db可以指定記錄的資料庫;使用binlog-ignore-db可以指定不記錄的資料庫。注意的是:binlog-do-db和binlog-ignore-db一次只指定一個資料庫,指定多個資料庫需要多個語句。而且,MySQL會將所有的資料庫名稱改成小寫,在指定資料庫時必須全部使用小寫名字,否則不會起作用。

  關掉這個功能只需要在他前面加上#號:#log-bin

  開啟慢查詢日誌( slow query log )

    慢查詢日誌對於跟蹤有問題的查詢非常有用。它記錄所有查過long_query_time的查詢,如果需要,還可以記錄不使用索引的記錄。下面是一個慢查詢日誌的例子:

  開啟慢查詢日誌,需要設定引數log_slow_queries、long_query_times、log-queries-not-using-indexes。

  log_slow_queries指定日誌檔案,如果不提供檔名,MySQL將自己產生預設檔名。long_query_times指定慢查詢的閾值,預設是10秒。log-queries-not-using-indexes是4.1.0以後引入的引數,它指示記錄不使用索引的查詢。筆者設定long_query_time=10

  設定:

  sort_buffer_size = 1M

  max_connections=120

  wait_timeout =120

  back_log=100

  read_buffer_size = 1M

  thread_cache=32

  interactive_timeout=120

  thread_concurrency = 4

  引數說明:

  back_log

  要求MySQL能有的連線數量。當主要MySQL執行緒在一個很短時間內得到非常多的連線請求,這就起作用,然後主執行緒花些時間(儘管很短) 檢查連線並且啟動一個新執行緒。back_log值指出在MySQL暫時停止回答新請求之前的短時間內多少個請求可以被存在堆疊中。只有如果期望在一個短時間內有很多連線,你需要增加它,換句話說,這值對到來的TCP/IP連線的偵聽佇列的大小。你的作業系統在這個佇列大小上有它自己的限制。 Unix listen(2)系統呼叫的手冊頁應該有更多的細節。檢查你的OS文件找出這個變數的最大值。試圖設定back_log高於你的作業系統的限制將是無效的。

  max_connections

  併發連線數目最大,120 超過這個值就會自動恢復,出了問題能自動解決

  thread_cache

  沒找到具體說明,不過設定為32後 20天才建立了400多個執行緒 而以前一天就建立了上千個執行緒 所以還是有用的

  thread_concurrency

  #設定為你的cpu數目x2,例如,只有一個cpu,那麼thread_concurrency=2

  #有2個cpu,那麼thread_concurrency=4

  skip-innodb

  #去掉innodb支援

  程式碼:

 

#   Example   MySQL   config   file   for   medium   systems.   
#   
#   This   is   for   a   system   with   little   memory   (32M   -   64M)   where   MySQL   plays   
#   an   important   part,   or   systems   up   to   128M   where   MySQL   is   used   together   with   
#   other   programs   (such   as   a   web   server)   
#   
#   You   can   copy   this   file   to   
#   /etc/my.cnf   to   set   global   options,   
#   mysql-data-dir/my.cnf   to   set   server-specific   options   (in   this   
#   installation   this   directory   is   /var/lib/mysql)   or   
#   ~/.my.cnf   to   set   user-specific   options.   
#   
#   In   this   file,   you   can   use   all   long   options   that   a   program   supports.   
#   If   you   want   to   know   which   options   a   program   supports,   run   the   program  
#   with   the   "--help"   option.   


#   The   following   options   will   be   passed   to   all   MySQL   clients   
[client]   
#password   =   your_password   
port   =   3306   
socket   =   /tmp/mysql.sock   
#socket   =   /var/lib/mysql/mysql.sock   
#   Here   follows   entries   for   some   specific   programs   


#   The   MySQL   server   
[mysqld]   
port   =   3306   
socket   =   /tmp/mysql.sock   
#socket   =   /var/lib/mysql/mysql.sock   
skip-locking   
key_buffer   =   128M   
max_allowed_packet   =   1M   
table_cache   =   256   
sort_buffer_size   =   1M   
net_buffer_length   =   16K   
myisam_sort_buffer_size   =   1M   
max_connections=120   
#addnew   config   
wait_timeout   =120   
back_log=100   
read_buffer_size   =   1M   
thread_cache=32   
skip-innodb   
skip-bdb   
skip-name-resolve   
join_buffer_size=512k   
query_cache_size   =   32M   
interactive_timeout=120   
long_query_time=10   
log_slow_queries=   /usr/local/mysql4/logs/slow_query.log   
query_cache_type=   1   
#   Try   number   of   CPU's*2   for   thread_concurrency   
thread_concurrency   =   4   


#end   new   config   
#   Don't   listen   on   a   TCP/IP   port   at   all.   This   can   be   a   security   enhancement,  
#   if   all   processes   that   need   to   connect   to   mysqld   run   on   the   same   host.   
#   All   interaction   with   mysqld   must   be   made   via   Unix   sockets   or   named   pipes.   
#   Note   that   using   this   option   without   enabling   named   pipes   on   Windows   
#   (via   the   "enable-named-pipe"   option)   will   render   mysqld   useless!   
#   
#skip-networking   


#   Replication   Master   Server   (default)   
#   binary   logging   is   required   for   replication   
#log-bin   


#   required   unique   id   between   1   and   2^32   -   1   
#   defaults   to   1   if   master-host   is   not   set   
#   but   will   not   function   as   a   master   if   omitted   
server-id   =   1   


#   Replication   Slave   (comment   out   master   section   to   use   this)   
#   
#   To   configure   this   host   as   a   replication   slave,   you   can   choose   between   
#   two   methods   :   
#   
#   1)   Use   the   CHANGE   MASTER   TO   command   (fully   described   in   our   manual)   -   
#   the   syntax   is:   
#   
#   CHANGE   MASTER   TO   MASTER_HOST=,   MASTER_PORT=,   
#   MASTER_USER=,   MASTER_PASSWORD=   ;   
#   
#   where   you   replace   ,   ,   by   quoted   strings   and   
#   by   the   master's   port   number   (3306   by   default).   
#   
#   Example:   
#   
#   CHANGE   MASTER   TO   MASTER_HOST='125.564.12.1',   MASTER_PORT=3306,   
#   MASTER_USER='joe',   MASTER_PASSWORD='secret';   
#   
#   OR   
#   
#   2)   Set   the   variables   below.   However,   in   case   you   choose   this   method,   then   
#   start   replication   for   the   first   time   (even   unsuccessfully,   for   example   
#   if   you   mistyped   the   password   in   master-password   and   the   slave   fails   to   
#   connect),   the   slave   will   create   a   master.info   file,   and   any   later   
#   change   in   this   file   to   the   variables'   values   below   will   be   ignored   and   
#   overridden   by   the   content   of   the   master.info   file,   unless   you   shutdown   
#   the   slave   server,   delete   master.info   and   restart   the   slaver   server.   
#   For   that   reason,   you   may   want   to   leave   the   lines   below   untouched   
#   (commented)   and   instead   use   CHANGE   MASTER   TO   (see   above)   
#   
#   required   unique   id   between   2   and   2^32   -   1   
#   (and   different   from   the   master)   
#   defaults   to   2   if   master-host   is   set   
#   but   will   not   function   as   a   slave   if   omitted   
#server-id   =   2   
#   
#   The   replication   master   for   this   slave   -   required   
#master-host   =   
#   
#   The   username   the   slave   will   use   for   authentication   when   connecting   
#   to   the   master   -   required   
#master-user   =   
#   
#   The   password   the   slave   will   authenticate   with   when   connecting   to   
#   the   master   -   required   
#master-password   =   
#   
#   The   port   the   master   is   listening   on.   
#   optional   -   defaults   to   3306   
#master-port   =   
#   
#   binary   logging   -   not   required   for   slaves,   but   recommended   
#log-bin   


#   Point   the   following   paths   to   different   dedicated   disks   
#tmpdir   =   /tmp/   
#log-update   =   /path-to-dedicated-directory/hostname   


#   Uncomment   the   following   if   you   are   using   BDB   tables   
#bdb_cache_size   =   4M   
#bdb_max_lock   =   10000   


#   Uncomment   the   following   if   you   are   using   InnoDB   tables   
#innodb_data_home_dir   =   /var/lib/mysql/   
#innodb_data_file_path   =   ibdata1:10M:autoextend   
#innodb_log_group_home_dir   =   /var/lib/mysql/   
#innodb_log_arch_dir   =   /var/lib/mysql/   
#   You   can   set   .._buffer_pool_size   up   to   50   -   80   %   
#   of   RAM   but   beware   of   setting   memory   usage   too   high   
#innodb_buffer_pool_size   =   16M   
#innodb_additional_mem_pool_size   =   2M   
#   Set   .._log_file_size   to   25   %   of   buffer   pool   size   
#innodb_log_file_size   =   5M   
#innodb_log_buffer_size   =   8M   
#innodb_flush_log_at_trx_commit   =   1   
#innodb_lock_wait_timeout   =   50   


[mysqldump]   
quick   
max_allowed_packet   =   16M   


[mysql]   
no-auto-rehash   
#   Remove   the   next   comment   character   if   you   are   not   familiar   with   SQL   
#safe-updates   


[isamchk]   
key_buffer   =   20M   
sort_buffer_size   =   20M   
read_buffer   =   2M   
write_buffer   =   2M   


[myisamchk]   
key_buffer   =   20M   
sort_buffer_size   =   20M   
read_buffer   =   2M   
write_buffer   =   2M   


[mysqlhotcopy]   
interactive-timeout

 

 

  補充

  優化table_cachetable_cache指定表快取記憶體的大小。每當MySQL訪問一個表時,如果在表緩衝區中還有空間,該表就被開啟並放入其中,這樣可以更快地訪問表內容。通過檢查峰值時間的狀態值Open_tables和Opened_tables,可以決定是否需要增加 table_cache的值。如果你發現open_tables等於table_cache,並且opened_tables在不斷增長,那麼你就需要增加table_cache的值了(上述狀態值可以使用SHOW STATUS LIKE ‘Open%tables’獲得)。注意,不能盲目地把table_cache設定成很大的值。如果設定得太高,可能會造成檔案描述符不足,從而造成效能不穩定或者連線失敗。對於有1G記憶體的機器,推薦值是128-256。

  案例1:該案例來自一個不是特別繁忙的伺服器

  table_cache – 512open_tables – 103opened_tables – 1273uptime – 4021421 (measured in seconds)該案例中table_cache似乎設定得太高了。在峰值時間,開啟表的數目比table_cache要少得多。

  案例2:該案例來自一臺開發伺服器。

  table_cache – 64open_tables – 64opened-tables – 431uptime – 1662790 (measured in seconds)雖然open_tables已經等於table_cache,但是相對於伺服器執行時間來說,opened_tables的值也非常低。因此,增加table_cache的值應該用處不大。案例3:該案例來自一個upderperforming的伺服器

  table_cache – 64open_tables – 64opened_tables – 22423uptime – 19538該案例中table_cache設定得太低了。雖然執行時間不到6小時,open_tables達到了最大值,opened_tables的值也非常高。這樣就需要增加table_cache的值。優化key_buffer_sizekey_buffer_size指定索引緩衝區的大小,它決定索引處理的速度,尤其是索引讀的速度。通過檢查狀態值Key_read_requests和Key_reads,可以知道key_buffer_size 設定是否合理。比例key_reads / key_read_requests應該儘可能的低,至少是1:100,1:1000更好(上述狀態值可以使用SHOW STATUS LIKE ‘key_read%’獲得)。key_buffer_size只對MyISAM表起作用。即使你不使用MyISAM表,但是內部的臨時磁碟表是 MyISAM表,也要使用該值。可以使用檢查狀態值created_tmp_disk_tables得知詳情。對於1G記憶體的機器,如果不使用 MyISAM表,推薦值是16M(8-64M)。

  案例1:健康狀況

  key_buffer_size – 402649088 (384M)key_read_requests – 597579931key_reads - 56188

  案例2:警報狀態

  key_buffer_size – 16777216 (16M)key_read_requests – 597579931key_reads - 53832731案例1中比例低於1:10000,是健康的情況。案例2中比例達到1:11,警報已經拉響。

 

相關文章