qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Mysql性能測試 Mysql性能

           網站訪問量越來越大,MySQL自然成為瓶頸。因此MySQL 的優化成為我們需要考慮的問題,第一步自然想到的是 MySQL 系統參數的優化,作為一個訪問量很大的網站(日20萬人次以上)的數據庫系統,不可能指望 MySQL 默認的系統參數能夠讓 MySQL運行得非常順暢。

            (1)、back_log: 要求MySQL 能有的連接數量。當主要MySQL線程在一個很短時間內得到非常多的連接請求,這就起作用,然后主線程花些時間(盡管很短)檢查連接并且啟動一個新線程。back_log值指出在MySQL暫時停止回答新請求之前的短時間內多少個請求可以被存在堆棧中。只有如果期望在一個短時間內有很多連接,你需要增加它,換句話說,這值對到來的TCP/IP連接的偵聽隊列的大小。你的操作系統在這個隊列大小上有它自己的限制。 試圖設定back_log高于你的操作系統的限制將是無效。當你觀察你的主機進程列表,發現大量 264084 | unauthenticated user |xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待連接進程時,就要加大 back_log的值了。默認數值是50,我把它改為500。

            (2)、interactive_timeout: 服務器在關閉它前在一個交互連接上等待行動的秒數。一個交互的客戶被定義為對mysql_real_connect()使用 CLIENT_INTERACTIVE 選項的客戶。默認數值是28800,我把它改為7200。

            (3)、key_buffer_size: 索引塊是緩沖的并且被所有的線程共享。key_buffer_size是用于索引塊的緩沖區大小,增加它可得到更好處理的索引(對所有讀和多重寫),到你能負擔得起那樣多。如果你使它太大,系統將開始換頁并且真的變慢了。默認數值是8388600(8M),我的MySQL主機有2GB內存,所以我把它改為402649088(400MB)。

            (4)、max_connections: 允許的同時客戶的數量。增加該值增加mysqld 要求的文件描述符的數量。這個數字應該增加,否則,你將經常看到 Toomany connections 錯誤。 默認數值是100,我把它改為1024 。

            (5)、record_buffer: 每個進行一個順序掃描的線程為其掃描的每張表分配這個大小的一個緩沖區。如果你做很多順序掃描,你可能想要增加該值。默認數值是131072(128K),我把它改為16773120 (16M)

            (6)、sort_buffer: 每個需要進行排序的線程分配該大小的一個緩沖區。增加這值加速ORDER BY或GROUP BY操作。默認數值是2097144(2M),我把它改為16777208 (16M)。

            (7)、table_cache: 為所有線程打開表的數量。增加該值能增加mysqld要求的文件描述符的數量。MySQL對每個唯一打開的表需要2個文件描述符。默認數值是64,我把它改為512。

            (8)、thread_cache_size: 可以復用的保存在中的線程的數量。如果有,新的線程從緩存中取得,當斷開連接的時候如果有空間,客戶的線置在緩存中。如果有很多新的線程,為了提高性能可以這個變量值。通過比較 Connections 和 Threads_created 狀態的變量,可以看到這個變量的作用。我把它設置為 80。

            (10)、wait_timeout: 服務器在關閉它之前在一個連接上等待行動的秒數。默認數值是28800,我把它改為7200。

            注:參數的調整可以通過修改/etc/my.cnf文件并重啟 MySQL 實現。這是一個比較謹慎的工作,上面的結果也僅僅是我的一些看法,你可以根據你自己主機的硬件情況(特別是內存大小)進一步修改。

           mysql> showglobal status;

            可以列出mysql服務器運行各種狀態值,另外,查詢mysql服務器配置信息語句:

            mysql> showvariables;

            一、慢查詢

          mysql> showvariables like ‘%slow%‘;
          +------------------+-------+
          | variable_name | value |
          +------------------+-------+
          |log_slow_queries | on |
          |slow_launch_time | 2 |
          +------------------+-------+
          mysql> showglobal status like ‘%slow%‘;
          +---------------------+-------+
          | variable_name | value |
          +---------------------+-------+
          |slow_launch_threads | 0 |
          | slow_queries | 4148 |
          +---------------------+-------+

            配置中打開了記錄慢查詢,執行時間超過2秒的即為慢查詢,系統顯示有4148個慢查詢,你可以分析慢查詢日志,找出有問題的sql語句,慢查詢時間不宜設置過長,否則意義不大,最好在5秒以內,如果你需要微秒級別的慢查詢,可以考慮給mysql打補丁:http://www.percona.com/docs/wiki/release:start,記得找對應的版本。

            打開慢查詢日志可能會對系統性能有一點點影響,如果你的mysql是主-從結構,可以考慮打開其中一臺從服務器的慢查詢日志,這樣既可以監控慢查詢,對系統性能影響又小。

            二、連接數

            經常會遇見”mysql: error 1040: too many connections”的情況,一種是訪問量確實很高,mysql服務器抗不住,這個時候就要考慮增加從服務器分散讀壓力,另外一種情況是mysql配置文件中max_connections值過小:

          mysql> show variables like ‘max_connections‘;
          +-----------------+-------+
          | variable_name | value |
          +-----------------+-------+
          | max_connections | 256 |
          +-----------------+-------+

            這臺mysql服務器最大連接數是256,然后查詢一下服務器響應的最大連接數:

            mysql服務器過去的最大連接數是245,沒有達到服務器連接數上限256,應該沒有出現1040錯誤,比較理想的設置是

            最大連接數占上限連接數的85%左右,如果發現比例在10%以下,mysql服務器連接數上限設置的過高了。

            三、key_buffer_size

            key_buffer_size是對myisam表性能影響最大的一個參數,下面一臺以myisam為主要存儲引擎服務器的配置:

          mysql> show variables like‘key_buffer_size‘;+-----------------+------------+
          | variable_name | value |
          +-----------------+------------+
          | key_buffer_size | 536870912 |
          +-----------------+------------+

            分配了512mb內存給key_buffer_size,我們再看一下key_buffer_size的使用情況:

          mysql> show global status like ‘key_read%‘;
          +------------------------+-------------+
          | variable_name | value |
          +------------------------+-------------+
          | key_read_requests | 27813678764 |
          | key_reads | 6798830 |
          +------------------------+-------------+

            一共有27813678764個索引讀取請求,有6798830個請求在內存中沒有找到直接從硬盤讀取索引,計算索引未命中緩存的概率:

            key_cache_miss_rate = key_reads / key_read_requests * 100%

            比如上面的數據,key_cache_miss_rate為0.0244%,4000個索引讀取請求才有一個直接讀硬盤,已經很bt了,key_cache_miss_rate在0.1%以下都很好(每1000個請求有一個直接讀硬盤),如果key_cache_miss_rate在0.01%以下的話,key_buffer_size分配的過多,可以適當減少。

            mysql服務器還提供了key_blocks_*參數:

          mysql> show global status like ‘key_blocks_u%‘;
          +------------------------+-------------+
          | variable_name | value |
          +------------------------+-------------+
          | key_blocks_unused | 0 |
          | key_blocks_used | 413543 |
          +------------------------+-------------+

            key_blocks_unused表示未使用的緩存簇(blocks)數,key_blocks_used表示曾經用到的最大的blocks數,比如這臺服務器,所有的緩存都用到了,要么增加key_buffer_size,要么就是過渡索引了,把緩存占滿了。比較理想的設置:

          key_blocks_used / (key_blocks_unused + key_blocks_used) * 100% ≈ 80%




          四、臨時表

          mysql> show global status like ‘created_tmp%‘;
          +-------------------------+---------+
          | variable_name | value |
          +-------------------------+---------+
          | created_tmp_disk_tables | 21197 |
          | created_tmp_files | 58 |
          | created_tmp_tables | 1771587 |
          +-------------------------+---------+

            每次創建臨時表,created_tmp_tables增加,如果是在磁盤上創建臨時表,created_tmp_disk_tables也增加,created_tmp_files表示mysql服務創建的臨時文件文件數,比較理想的配置是:

            created_tmp_disk_tables /created_tmp_tables * 100% <= 25%比如上面的服務器created_tmp_disk_tables / created_tmp_tables * 100% = 1.20%,應該相當好了。我們再看一下mysql服務器對臨時表的配置:

          mysql> show variables where variable_name in (‘tmp_table_size‘,‘max_heap_table_size‘);
          +---------------------+-----------+
          | variable_name | value |
          +---------------------+-----------+
          | max_heap_table_size | 268435456 |
          | tmp_table_size | 536870912 |
          +---------------------+-----------+

            只有256mb以下的臨時表才能全部放內存,超過的就會用到硬盤臨時表。

            五、open table情況

          mysql> show global status like ‘open%tables%‘;
          +---------------+-------+
          | variable_name | value |
          +---------------+-------+
          | open_tables | 919 |
          | opened_tables | 1951 |
          +---------------+-------+

            open_tables表示打開表的數量,opened_tables表示打開過的表數量,如果opened_tables數量過大,說明配置中table_cache(5.1.3之后這個值叫做table_open_cache)值可能太小,我們查詢一下服務器table_cache值:

          mysql> show variables like ‘table_cache‘;
          +---------------+-------+
          | variable_name | value |
          +---------------+-------+
          | table_cache | 2048 |
          +---------------+-------+

            比較合適的值為:

          open_tables / opened_tables * 100% >= 85%
          open_tables / table_cache * 100% <= 95%

            六、進程使用情況

          mysql> show global status like ‘thread%‘;
          +-------------------+-------+
          | variable_name | value |
          +-------------------+-------+
          | threads_cached | 46 |
          | threads_connected | 2 |
          | threads_created | 570 |
          | threads_running | 1 |
          +-------------------+-------+

            如果我們在mysql服務器配置文件中設置了thread_cache_size,當客戶端斷開之后,服務器處理此客戶的線程將會緩存起來以響應下一個客戶而不是銷毀(前提是緩存數未達上限)。threads_created表示創建過的線程數,如果發現threads_created值過大的話,表明mysql服務器一直在創建線程,這也是比較耗資源,可以適當增加配置文件中thread_cache_size值,查詢服務器thread_cache_size配置:

          mysql> show variables like ‘thread_cache_size‘;
          +-------------------+-------+
          | variable_name | value |
          +-------------------+-------+
          | thread_cache_size | 64 |
          +-------------------+-------+

            示例中的服務器還是挺健康的。

            七、查詢緩存(query cache)

          mysql> show global status like ‘qcache%‘;
          +-------------------------+-----------+
          | variable_name | value |
          +-------------------------+-----------+
          | qcache_free_blocks | 22756 |
          | qcache_free_memory | 76764704 |
          | qcache_hits | 213028692 |
          | qcache_inserts | 208894227 |
          | qcache_lowmem_prunes | 4010916 |
          | qcache_not_cached | 13385031 |
          | qcache_queries_in_cache | 43560 |
          | qcache_total_blocks | 111212 |
          +-------------------------+-----------+

            mysql查詢緩存變量解釋:

            qcache_free_blocks:緩存中相鄰內存塊的個數。數目大說明可能有碎片。flush query cache會對緩存中的碎片進行整理,從而得到一個空閑塊。

            qcache_free_memory:緩存中的空閑內存。

            qcache_hits:每次查詢在緩存中命中時就增大

            qcache_inserts:每次插入一個查詢時就增大。命中次數除以插入次數就是不中比率。

            qcache_lowmem_prunes:緩存出現內存不足并且必須要進行清理以便為更多查詢提供空間的次數。這個數字最好長時間來看;如果這個數字在不斷增長,就表示可能碎片非常嚴重,或者內存很少。(上面的 free_blocks和free_memory可以告訴您屬于哪種情況)

            qcache_not_cached:不適合進行緩存的查詢的數量,通常是由于這些查詢不是 select 語句或者用了now()之類的函數。

            qcache_queries_in_cache:當前緩存的查詢(和響應)的數量。

            qcache_total_blocks:緩存中塊的數量。

            我們再查詢一下服務器關于query_cache的配置:

          mysql> show variables like ‘query_cache%‘;
          +------------------------------+-----------+
          | variable_name | value |
          +------------------------------+-----------+
          | query_cache_limit | 2097152 |
          | query_cache_min_res_unit | 4096 |
          | query_cache_size | 203423744 |
          | query_cache_type | on |
          | query_cache_wlock_invalidate | off |
          +------------------------------+-----------+

            各字段的解釋:

            query_cache_limit:超過此大小的查詢將不緩存

            query_cache_min_res_unit:緩存塊的最小大小

            query_cache_size:查詢緩存大小

            query_cache_type:緩存類型,決定緩存什么樣的查詢,示例中表示不緩存 select sql_no_cache 查詢

            query_cache_wlock_invalidate:當有其他客戶端正在對myisam表進行寫操作時,如果查詢在query cache中,是否返回cache結果還是等寫操作完成再讀表獲取結果。

            query_cache_min_res_unit的配置是一柄”雙刃劍”,默認是4kb,設置值大對大數據查詢有好處,但如果你的查詢都是小數據查詢,就容易造成內存碎片和浪費。

            查詢緩存碎片率 = qcache_free_blocks /qcache_total_blocks * 100%

            如果查詢緩存碎片率超過20%,可以用flush query cache整理緩存碎片,或者試試減小query_cache_min_res_unit,如果你的查詢都是小數據量的話。

            查詢緩存利用率 = (query_cache_size -qcache_free_memory) / query_cache_size * 100%

            查詢緩存利用率在25%以下的話說明query_cache_size設置的過大,可適當減小;查詢緩存利用率在80%以上而且qcache_lowmem_prunes> 50的話說明query_cache_size可能有點小,要不就是碎片太多。

            查詢緩存命中率 = (qcache_hits - qcache_inserts) /qcache_hits * 100%

            示例服務器查詢緩存碎片率= 20.46%,查詢緩存利用率= 62.26%,查詢緩存命中率= 1.94%,命中率很差,可能寫操作比較頻繁吧,而且可能有些碎片。

           八、排序使用情況

          mysql> show global status like ‘sort%‘;
          +-------------------+------------+
          | variable_name | value |
          +-------------------+------------+
          | sort_merge_passes | 29 |
          | sort_range | 37432840 |
          | sort_rows | 9178691532 |
          | sort_scan | 1860569 |
          +-------------------+------------+

            sort_merge_passes 包括兩步。mysql 首先會嘗試在內存中做排序,使用的內存大小由系統變量 sort_buffer_size 決定,如果它的大小不夠把所有的記錄都讀到內存中,mysql 就會把每次在內存中排序的結果存到臨時文件中,等 mysql 找到所有記錄之后,再把臨時文件中的記錄做一次排序。這再次排序就會增加 sort_merge_passes。實際上,mysql 會用另一個臨時文件來存再次排序的結果,所以通常會看到 sort_merge_passes 增加的數值是建臨時文件數的兩倍。因為用到了臨時文件,所以速度可能會比較慢,增加 sort_buffer_size 會減少 sort_merge_passes 和創建臨時文件的次數。但盲目的增加 sort_buffer_size 并不一定能提高速度,見 how fast can you sort data with mysql?(引自http://qroom.blogspot.com/2007/09/mysql-select-sort.html,貌似被墻)

            另外,增加read_rnd_buffer_size(3.2.3是record_rnd_buffer_size)的值對排序的操作也有一點的好處,參見http://www.mysqlperformanceblog.com/2007/07/24/what-exactly-is-read_rnd_buffer_size/

            九、文件打開數(open_files)

          mysql> show global status like ‘open_files‘;
          +---------------+-------+
          | variable_name | value |
          +---------------+-------+
          | open_files | 1410 |
          +---------------+-------+
          mysql> show variables like ‘open_files_limit‘;
          +------------------+-------+
          | variable_name | value |
          +------------------+-------+
          | open_files_limit | 4590 |
          +------------------+-------+

            比較合適的設置:open_files / open_files_limit * 100%<= 75%

            十、表鎖情況

          mysql> show global status like ‘table_locks%‘;
          +-----------------------+-----------+
          | variable_name | value |
          +-----------------------+-----------+
          | table_locks_immediate | 490206328 |
          | table_locks_waited | 2084912 |
          +-----------------------+-----------+

            table_locks_immediate表示立即釋放表鎖數,table_locks_waited表示需要等待的表鎖數,如果table_locks_immediate /table_locks_waited > 5000,最好采用innodb引擎,因為innodb是行鎖而myisam是表鎖,對于高并發寫入的應用innodb效果會好些。示例中的服務器table_locks_immediate/ table_locks_waited = 235,myisam就足夠了。

            十一、表掃描情況

          mysql>showglobalstatuslike‘handler_read%‘;
          +-----------------------+-------------+
          |variable_name|value|
          +-----------------------+-------------+
          |handler_read_first|5803750|
          |handler_read_key|6049319850|
          |handler_read_next|94440908210|
          |handler_read_prev|34822001724|
          |handler_read_rnd|405482605|
          |handler_read_rnd_next|18912877839|
          +-----------------------+-------------+

            各字段解釋參見http://hi.baidu.com/thinkinginlamp/blog/item/31690cd7c4bc5cdaa144df9c.html,調出服務器完成的查詢請求次數:

          mysql> show global status like ‘com_select‘;
          +---------------+-----------+
          | variable_name | value |
          +---------------+-----------+
          | com_select | 222693559 |
          +---------------+-----------+

            計算表掃描率:

            表掃描率= handler_read_rnd_next / com_select

            如果表掃描率超過4000,說明進行了太多表掃描,很有可能索引沒有建好,增加read_buffer_size值會有一些好處,但最好不要超過8mb。

            后記:

            文中提到一些數字都是參考值,了解基本原理就可以,除了mysql提供的各種status值外,操作系統的一些性能指標也很重要,比如常用的top,iostat等,尤其是iostat,現在的系統瓶頸一般都在磁盤io上,關于iostat的使用

           網站訪問量越來越大,MySQL自然成為瓶頸。因此MySQL 的優化成為我們需要考慮的問題,第一步自然想到的是 MySQL 系統參數的優化,作為一個訪問量很大的網站(日20萬人次以上)的數據庫系統,不可能指望 MySQL 默認的系統參數能夠讓 MySQL運行得非常順暢。

            (1)、back_log: 要求MySQL 能有的連接數量。當主要MySQL線程在一個很短時間內得到非常多的連接請求,這就起作用,然后主線程花些時間(盡管很短)檢查連接并且啟動一個新線程。back_log值指出在MySQL暫時停止回答新請求之前的短時間內多少個請求可以被存在堆棧中。只有如果期望在一個短時間內有很多連接,你需要增加它,換句話說,這值對到來的TCP/IP連接的偵聽隊列的大小。你的操作系統在這個隊列大小上有它自己的限制。 試圖設定back_log高于你的操作系統的限制將是無效。當你觀察你的主機進程列表,發現大量 264084 | unauthenticated user |xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待連接進程時,就要加大 back_log的值了。默認數值是50,我把它改為500。

            (2)、interactive_timeout: 服務器在關閉它前在一個交互連接上等待行動的秒數。一個交互的客戶被定義為對mysql_real_connect()使用 CLIENT_INTERACTIVE 選項的客戶。默認數值是28800,我把它改為7200。

            (3)、key_buffer_size: 索引塊是緩沖的并且被所有的線程共享。key_buffer_size是用于索引塊的緩沖區大小,增加它可得到更好處理的索引(對所有讀和多重寫),到你能負擔得起那樣多。如果你使它太大,系統將開始換頁并且真的變慢了。默認數值是8388600(8M),我的MySQL主機有2GB內存,所以我把它改為402649088(400MB)。

            (4)、max_connections: 允許的同時客戶的數量。增加該值增加mysqld 要求的文件描述符的數量。這個數字應該增加,否則,你將經常看到 Toomany connections 錯誤。 默認數值是100,我把它改為1024 。

            (5)、record_buffer: 每個進行一個順序掃描的線程為其掃描的每張表分配這個大小的一個緩沖區。如果你做很多順序掃描,你可能想要增加該值。默認數值是131072(128K),我把它改為16773120 (16M)

            (6)、sort_buffer: 每個需要進行排序的線程分配該大小的一個緩沖區。增加這值加速ORDER BY或GROUP BY操作。默認數值是2097144(2M),我把它改為16777208 (16M)。

            (7)、table_cache: 為所有線程打開表的數量。增加該值能增加mysqld要求的文件描述符的數量。MySQL對每個唯一打開的表需要2個文件描述符。默認數值是64,我把它改為512。

            (8)、thread_cache_size: 可以復用的保存在中的線程的數量。如果有,新的線程從緩存中取得,當斷開連接的時候如果有空間,客戶的線置在緩存中。如果有很多新的線程,為了提高性能可以這個變量值。通過比較 Connections 和 Threads_created 狀態的變量,可以看到這個變量的作用。我把它設置為 80。

            (10)、wait_timeout: 服務器在關閉它之前在一個連接上等待行動的秒數。默認數值是28800,我把它改為7200。

            注:參數的調整可以通過修改/etc/my.cnf文件并重啟 MySQL 實現。這是一個比較謹慎的工作,上面的結果也僅僅是我的一些看法,你可以根據你自己主機的硬件情況(特別是內存大小)進一步修改。

           

          posted on 2013-07-03 11:07 順其自然EVO 閱讀(363) 評論(0)  編輯  收藏 所屬分類: 數據庫性能測試

          <2013年7月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 洞头县| 县级市| 柏乡县| 黔南| 南陵县| 德庆县| 章丘市| 安丘市| 那坡县| 漳平市| 平顶山市| 方正县| 汝阳县| 保山市| 襄汾县| 焉耆| 大足县| 布拖县| 湄潭县| 鄱阳县| 永和县| 金门县| 巴彦淖尔市| 石林| 西乡县| 绿春县| 清流县| 万荣县| 广河县| 巨野县| 吉木萨尔县| 大埔区| 南召县| 南开区| 雅江县| 平陆县| 永清县| 五常市| 莱州市| 江津市| 雅江县|