mysql 性能剖析

1. 首先我們進行OS層面的檢查

  一般來說最容易成爲瓶頸的是磁盤I/O子系統,因爲它的讀寫速度通常是最慢的。

1)查看系統整體負載可以使用 w 或者 sar -u 2 10 或者top命令查看

[root@localhost sql-bench]# w
  19:07:10 up 10 days,  8:36,  5 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/2    192.168.1.249    01:11   17:55m  0.00s  0.00s -bash
oracle   :0                        23Dec16 ?xdm?   4:13   0.20s /usr/bin/gnome-session
oracle   pts/1    :0.0             23Dec16  9days  0.09s  0.09s bash
root     pts/3    192.168.1.249    Thu21    0.00s  1.45s  0.00s w
root     pts/5    192.168.1.249    Thu21   17:36m 48:12   0.01s -bash

· 或者使用 sar -q 1

[root@localhost sql-bench]# sar -q 1
Linux 2.6.18-412.el5 (localhost.localdomain)2017年01月01日


19時11分06秒   runq-sz  plist-sz   ldavg-1   ldavg-5  ldavg-15
19時11分07秒         0       239      0.00      0.00      0.00
Average:            0       239      0.00      0.00      0.00


[root@localhost sql-bench]# sar -u 2 10   頻率2秒一次收集10次
Linux 2.6.18-412.el5 (localhost.localdomain)2017年01月01日


19時08分10秒       CPU     %user     %nice   %system   %iowait    %steal     %idle
19時08分12秒       all      0.00      0.00      1.02      0.00      0.00     98.98
19時08分14秒       all      0.00      0.00      0.00      0.00      0.00    100.00
19時08分16秒       all      0.00      0.00      0.52      0.00      0.00     99.48
19時08分18秒       all      0.00      0.00      0.00      0.00      0.00    100.00
19時08分20秒       all      0.00      0.00      0.51      0.00      0.00     99.49
19時08分22秒       all      0.00      0.00      0.52      0.00      0.00     99.48
19時08分24秒       all      0.00      0.00      0.00      0.00      0.00    100.00
19時08分26秒       all      0.00      0.00      0.51      0.00      0.00     99.49
19時08分28秒       all      0.00      0.00      0.00      0.00      0.00    100.00
19時08分30秒       all      0.00      0.00      1.02      0.00      0.00     98.98
Average:          all      0.00      0.00      0.41      0.00      0.00     99.59

2)對整理負載有了一定的瞭解後,查看瓶頸處在哪個子系統

[root@localhost ~]# top
top - 19:15:33 up 10 days,  8:44,  5 users,  load average: 2.76, 0.66, 0.21
Tasks: 146 total,   2 running, 143 sleeping,   0 stopped,   1 zombie
Cpu(s):  3.4%us,  2.7%sy,  0.0%ni,  0.0%id, 93.2%wa,  0.3%hi,  0.3%si,  0.0%st
Mem:   2058768k total,  2047764k used,    11004k free,   102848k buffers
Swap:  2064376k total,   362832k used,  1701544k free,   551036k cached


  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                             
  375 mysql     15   0  864m 574m 7660 S  6.0 28.6  48:14.78 mysqld                                               
25969 oracle    15   0 90100  988  568 S  0.3  0.0   0:02.86 scim-launcher                                        
28477 root      17   0  106m 3320 1800 S  0.3  0.2   0:00.10 sysbench                                             
  1 root      15   0 10372  688  580 S  0.0  0.0   0:01.29 init                                                 
    2 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0                                          
    3 root      34  19     0    0    0 S  0.0  0.0   0:00.10 ksoftirqd/0                                          
    4 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 watchdog/0                                           
    5 root      10  -5     0    0    0 S  0.0  0.0   0:06.30 events/0                                             
    6 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khelper                                              
   23 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kthread                                              
    27 root      10  -5     0    0    0 S  0.0  0.0   0:01.51 kblockd/0                                            
    28 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 kacpid                                               
    65 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 cqueue/0                                             
    68 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khubd                                                
    70 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kseriod                                              
明顯是mysqld進程導致負載過高,%us 和 %wa 的值較高,表示當前比較大的瓶頸可能是在用戶進程消耗的CPU以及磁盤I/O等待上。

 查看磁盤IO

[root@localhost ~]#  sar -d  1
Linux 2.6.18-412.el5 (localhost.localdomain) 2017年01月01日
19時19分05秒       DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
19時19分06秒    dev3-0     86.46     66.67   4541.67     53.30     32.07    559.35     11.81    102.08
19時19分06秒    dev3-1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
19時19分06秒    dev3-2     86.46     66.67   4541.67     53.30     32.07    559.35     11.81    102.08
19時19分06秒  dev253-0    521.88     75.00   4150.00      8.10    111.58    428.49      1.96    102.08
19時19分06秒  dev253-1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
19時19分06秒   dev22-0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:          DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
Average:       dev3-0     86.46     66.67   4541.67     53.30     32.07    559.35     11.81    102.08
Average:       dev3-1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:       dev3-2     86.46     66.67   4541.67     53.30     32.07    559.35     11.81    102.08
Average:     dev253-0    521.88     75.00   4150.00      8.10    111.58    428.49      1.96    102.08
Average:     dev253-1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:      dev22-0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

確認到底哪些進程消耗的磁盤I/O資源最多

可以看到mysql實例消耗IO最多,接下來看看都是哪些sql在運行。

2、mysql層面剖析

1)首先查看當前正在執行的sql

[root@localhost ~]# mysqladmin -uroot -proot -h127.0.0.1 pr|grep -v Sleep
Warning: Using a password on the command line interface can be insecure.
+----+------+-----------------+-------+---------+------+----------+--------------------------------+
| Id | User | Host            | db    | Command | Time | State    | Info                           |
+----+------+-----------------+-------+---------+------+----------+--------------------------------+
| 18 | root | localhost:27124 | zycDB | Execute | 0    | updating | UPDATE tt set k=k+1 where id=? |
| 19 | root | localhost:27125 | zycDB | Execute | 0    | updating | UPDATE tt set k=k+1 where id=? |
| 20 | root | localhost:27126 | zycDB | Execute | 0    | init     | COMMIT                         |
| 21 | root | localhost:27127 | zycDB | Execute | 0    | updating | UPDATE tt set k=k+1 where id=? |
| 22 | root | localhost:27128 | zycDB | Execute | 0    | init     | COMMIT                         |
| 23 | root | localhost:27129 | zycDB | Execute | 0    | init     | COMMIT                         |
| 24 | root | localhost:27130 | zycDB | Execute | 0    | init     | COMMIT                         |
| 25 | root | localhost:27131 | zycDB | Execute | 0    | updating | UPDATE tt set k=k+1 where id=? |
| 26 | root | localhost:27140 |       | Query   | 0    | init     | show processlist               |
+----+------+-----------------+-------+---------+------+----------+--------------------------------+

關注time列參數,分析用戶進程佔用mysql連接數時長


如果運行的SQL語句太多,運行時間太長,說明mysql效率有問題。必要時可以將相應的進程kill掉。
kill 287662;

2)mysql參數檢測

(1)connect_timeout
指定mysql服務等待應答連接的最大時間,單位s,默認10秒,超過這個時間mysql向客戶端返回bad handshake。內網高併發環境下,

建議設置10-15s,避免bad handshake。並且關注thread_cache_size,設置爲非0,具體大小視環境定。

(2)skip-name-resolve
避免域名解析,可以大大加快用戶獲取連接的速度,特別是在網絡較差的情況下。mysql收到用戶發來的請求連接時,會根據請求包中

獲得的ip來反向查詢請求者的主機名,然後會更具返回的主機名有一次去查詢ip,如果兩次獲得的ip相同,則成功建立連接。在DNS不

穩定或者局域網主機過多的情況下,建立一次成功的請求連接必然會消耗很多不必要的時間。但是加入mysql服務器的ip是廣域網地址,

最好不要設置skip-name-resolve.

(3)slave-net-timeout=seconds
當slave從master讀取binlog失敗後,等待多長時間,重新與master建立連接,並獲取數據。默認3600s,如果保證數據能夠及時同步,該參數應設置在10s以下。
show variables like ‘%timeout%‘;
set global slave_net_timeout = 5;

(4)master-connect-retry=seconds

當主從連接建立失敗,間隔多久重試。默認60s,合理設置該參數。

(5)連接數max_connections
如果連接數達到最大連接數,那不管剩餘多少資源,用戶的連接請求都會阻塞在外面。
max_connections,最大連接數,默認151,一般經驗設置3000。win服務器連接數支持1500-1800,linux服務器可以支持8000個左右。
另外設置max_user_connections=0,表示不限制用戶的最大連接數,其最大值可以等於max_connections
show variables like '%connections%';
show global status like 'max_used_connections';

    檢查曾經使用最大的連接數,這個值在max_connections的85%左右比較合適,過高,則會系統使用連接數過少,系統負荷過高。

3)事務和鎖

事務等待狀況

SELECT     r.trx_id waiting_trx_id,r.trx_mysql_thread_id waiting_thread,r.trx_query waiting_query,b.trx_id blocking_trx_id,
      b.trx_mysql_thread_id blocking_thread,b.trx_query blocking_query FROM
      information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

查看未關閉的事務

SELECT     a.trx_id,a.trx_state,a.trx_started,a.trx_query,b.ID,b.USER,b.HOST,b.DB,b.COMMAND,b.TIME,b.STATE,b.INFO FROM 
information_schema.INNODB_TRX aLEFT JOIN information_schema.PROCESSLIST b ON a.trx_mysql_thread_id = b.idWHERE     b.COMMAND = 'Sleep';

段時間內爲關閉的事務

SELECT trx_id,trx_started,trx_mysql_thread_id
FROM INFORMATION_SCHEMA.INNODB_TRX
WHERE trx_started < date_sub(now(), INTERVAL 1 MINUTE)
AND trx_operation_state IS NULL
AND trx_query IS NULL;

系統鎖狀況

show status like '%lock%';

4)慢查詢

mysql> show variables like '%slow%’;
+———————+—————————————--------------------+
| Variable_name       | Value                                                  |
+———————+—————————————---------------------+
| log_slow_queries    | OFF                                                    |
| slow_launch_time    | 2                                                        |
| slow_query_log      | OFF                                                     |
| slow_query_log_file | /data0/mysql/3306/data/mysql1-slow.log |
+———————+—————————————----------------------+

5)key_buffer_size索引緩存
key_buffer_size是對myISAM表性能影響最大的一個參數。
mysql> show global status like 'key_read%';
+-------------------+----------+
| Variable_name     | Value    |
+-------------------+----------+
| Key_read_requests | 13915643 |
| Key_reads         | 129954   |
+-------------------+----------+
key_read_requests表示總共的索引請求數,key_reads表示請求在內存中沒有找到,直接從硬盤讀取索引,計算索引未命中緩存:
key_cache_miss_rate=key_reads/key_read_requests*100%
保持key_cache_miss_rate在0.1%以下都是很好的,如果在0.01%以下的話,key_buffer_size分配過的,適當減少。

6)created_tmp_tables 創建臨時表
mysql> show global status like 'created_tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 540   |
| Created_tmp_files       | 211   |
| Created_tmp_tables      | 2302  |
+-------------------------+-------+
3 rows in set (0.00 sec)
每次創建臨時表,created_tmp_tables增加(內存&磁盤創建臨時表),created_tmp_disk_tables磁盤創建的臨時表,比較理想的配置:
created_tmp_disk_tables/created_tmp_tables*100%<=25%
臨時表配置參數:
show variables where variable_name in ('tmp_table_size','max_heap_table_size');
+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| max_heap_table_size | 16777216 |
| tmp_table_size      | 16777216 |
+---------------------+----------+

2 rows in set (0.00 sec)
只有16MB的臨時表才能全部放內存,超過的就會用到硬盤臨時表。

7)open_tables打開表數量

mysql> show global status like '%open%table%';

+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Com_show_open_tables     | 0     |
| Open_table_definitions   | 64    |
| Open_tables              | 64    |
| Opened_table_definitions | 76    |
| Opened_tables            | 5402  |
| Slave_open_temp_tables   | 0     |
+--------------------------+-------+
6 rows in set (0.00 sec)
open_tables表示打開表的數量,opened_tables表示曾經打開過的表數量。
如果opened_tables數量過大,說明配置table_open_cache緩存值可能太小,查詢table_open_cache參數設置值:
mysql> show variables like 'table%cache%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| table_definition_cache | 400   |
| table_open_cache       | 64    |
+------------------------+-------+
2 rows in set (0.00 sec)

比較合適的值:
85% <= open_tables / opened_tables <= 95%

8)thread_cache_size  線程緩存

mysql> show global status like 'thread%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Threadpool_idle_threads | 0        |
| Threadpool_threads      | 0        |
| Threads_cached          | 0        |
| Threads_connected       | 48       |
| Threads_created         | 15023416 |
| Threads_running         | 6        |
+-------------------------+----------+
6 rows in set (0.00 sec)

如果配置thread_cache_size後,當客戶端端口連接後,服務器處理客戶的線程將會緩存到thread_cache中,
以響應下一個客戶,而不是銷燬(前提緩存數未達到thread_cache_size上線)。threads_created表示曾經
創建的線程數,如果發現threads_created值過大,表明mysql服務器一直在創建線程,這個比較耗資源,可
以適當增加thread_cache_size值

mysql> show variables like 'thread_cache_size';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 0     |
+-------------------+-------+
1 row in set (0.00 sec

9)query cache 查詢緩存

mysql> show global status like 'qcache%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_free_blocks      | 0     |
| Qcache_free_memory      | 0     |
| Qcache_hits             | 0     |
| Qcache_inserts          | 0     |
| Qcache_lowmem_prunes    | 0     |
| Qcache_not_cached       | 0     |
| Qcache_queries_in_cache | 0     |
| Qcache_total_blocks     | 0     |
+-------------------------+-------+
8 rows in set (0.00 sec)

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:緩存中塊的數量。

mysql> show variables like 'query_cache%';

+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 0       |
| query_cache_strip_comments   | OFF     |
| query_cache_type             | ON      |
| query_cache_wlock_invalidate | OFF     |
+------------------------------+---------+
6 rows in set (0.00 sec)

各字段的解釋:
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%,命中率很差,可能寫操作比較頻繁吧,而且可能有些碎片。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章