1. 程式人生 > >Mysql資料庫insert報慢查詢

Mysql資料庫insert報慢查詢

原文:http://blog.csdn.net/mchdba/article/details/77758316

同事報告說有個cdb mysql例項最近很慢,寫入速度巨慢,而且是間歇性的有的時候每隔7到8分鐘就卡一會,有的時候每隔12分鐘就卡一會,問他們是否有定時任務在拉資料?他們說沒有。

那是否有很多比較慢的sql把io資源消耗光了呢,去看慢查詢記錄,結果發現一條select都沒有,反而是有很多insert語句,見鬼啦,這咋回事呢?


慢查詢有很多記錄,如下所示,insert on duplicate key update,粗粗一看,肯定是on duplicate key update的問題,如下:

# [email protected]: hsh_ext[hsh_ext] @  [devtest.yikan.com]  Id: 37459
# Query_time: 1.170256  Lock_time: 0.000118 Rows_sent: 0  Rows_examined: 0
SET timestamp=1504065495;
/*id:57539043*/insert into hy_deive(record_time, platform, device_id,
    install_id, device_token, push_enabled,
    `uid`, model, app_version, is_login, device_type, created_at,
    updated_at)
    values
( 1504065494, 'android', '863049030002995', '417e03c9-b879-4741-86b6-beb8c1f42497', 'Anj6kMy77g-2sKlb7idPuxAQ58eXdE_JILDvT-xITBfb', 0, 4234883169, 'OPPO', '3.36.2', 1, 'umeng', 1504065494, 1504065494 ) , ( 1504065494, 'android', '863049030002995', '417e03c9-b879-4741-86b6-beb8c1f42497'
, 'F5nrlikA1gCLSrLZ7Xby1ASn+fXqSJZ3xATxvkJtXzU=', 0, 4234883169, 'OPPO', '3.36.2', 1, 'xiaomi', 1504065494, 1504065494 ) , ( 1504065494, 'android', '863049030002995', '417e03c9-b879-4741-86b6-beb8c1f42497', '0863049030002995200000184200CN01', 0, 4234883169, 'OPPO', '3.36.2', 1, 'huawei', 1504065494, 1504065494 ) on duplicate key update record_time = IF(record_time > values(record_time), record_time, values(record_time)), platform = IF(record_time > values(record_time), platform, values(platform)), install_id = IF(record_time > values(record_time), install_id, values(install_id)), device_token = IF(record_time > values(record_time), device_token, values(device_token)), push_enabled = IF(record_time > values(record_time), push_enabled, values(push_enabled)), model = IF(record_time > values(record_time), model, values(model)), app_version = IF(record_time > values(record_time), app_version, values(app_version)), is_login = IF(record_time > values(record_time), is_login, values(is_login)), updated_at = IF(record_time > values(record_time), updated_at, values(updated_at));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

但是實際上,準備2條無用的insert into … values… on duplicate key update …..,很快就執行完了,不到0.01s,那為啥那個時候,還有那麼多的慢查詢記錄呢?


去查看了cdb的監控記錄,select、udpate、insert沒有啥間隙性的尖刀出現,雖然有起伏有上升空間,但是都比較平穩,沒有尖刀,大家看下面的圖L
這裡寫圖片描述

這裡寫圖片描述



想到既然是insert語句,那麼就去看binlog日誌吧,看下所有的binlog日誌,看看那個卡的時間點,到底都執行了些啥操作呢?


結果一看binlog列表,發現binlog每隔8分鐘就會flush下,而這個flush的時間和慢查詢的時間正好吻合。

binlog日誌生成時間:
這裡寫圖片描述


慢查詢記錄時間:
這裡寫圖片描述


OK,那麼問題很明顯了,binlog日誌太大,flush的時候導致binlog寫入時間變慢,因為要寫入新的binlog,需要時間。解決方案就是調整binlog最大值,將1G降低到128M。

mysql> show variables like 'max_binlog_size';
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| max_binlog_size | 1073741824 |
+-----------------+------------+
1 row in set (0.01 sec)

mysql> select 128*1024*1024;
+---------------+
| 128*1024*1024 |
+---------------+
|     134217728 |
+---------------+
1 row in set (0.01 sec)

mysql> set global max_binlog_size=134217728;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'max_binlog_size';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| max_binlog_size | 134217728 |
+-----------------+-----------+
1 row in set (0.00 sec)

mysql> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

之後觀察了3個小時,再也沒有比較慢的insert語句了,而且開發那麼反應這段時間也基本沒有卡頓的現象了,事情暫時解決了,告一段落啦。


反思,網際網路場景中,max_binlog_size值確實不宜過大,這點需要謹記。



問題擴充套件:

檢視當前正在使用的binlog快取情況:

MySQL:(none) 13:07:41> show global status like 'bin%';
+----------------------------+-----------+
| Variable_name              | Value     |
+----------------------------+-----------+
| Binlog_cache_disk_use      | 1335001   |
| Binlog_cache_use           | 264238120 |
| Binlog_stmt_cache_disk_use | 0         |
| Binlog_stmt_cache_use      | 33        |
+----------------------------+-----------+
4 rows in set (0.00 sec)

MySQL:(none) 13:07:46> show global status like 'bin%';
+----------------------------+-----------+
| Variable_name              | Value     |
+----------------------------+-----------+
| Binlog_cache_disk_use      | 1335006   |
| Binlog_cache_use           | 264240359 |
| Binlog_stmt_cache_disk_use | 0         |
| Binlog_stmt_cache_use      | 33        |
+----------------------------+-----------+
4 rows in set (0.00 sec)

MySQL:(none) 13:07:47> 
MySQL:(none) 13:07:48> show global status like 'bin%';
+----------------------------+-----------+
| Variable_name              | Value     |
+----------------------------+-----------+
| Binlog_cache_disk_use      | 1335428   |
| Binlog_cache_use           | 264437761 |
| Binlog_stmt_cache_disk_use | 0         |
| Binlog_stmt_cache_use      | 33        |
+----------------------------+-----------+
4 rows in set (0.00 sec)

MySQL:(none) 13:09:28>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35


檢視binlog的cache設定:

MySQL:(none) 13:10:58> show variables like '%binlog_cache%';
+-----------------------+----------------------+
| Variable_name         | Value                |
+-----------------------+----------------------+
| binlog_cache_size     | 32768                |
| max_binlog_cache_size | 18446744073709547520 |
+-----------------------+----------------------+
2 rows in set (0.00 sec)

MySQL:(none) 13:11:13> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


binlog_cache_size:

為每個session 分配的記憶體,在事務過程中用來儲存二進位制日誌的快取。binlog_cache_disk_use表示因為我們binlog_cache_size設計的記憶體不足導致快取二進位制日誌用到了臨時檔案的次數;binlog_cache_use表示 用binlog_cache_size快取的次數;當對應的Binlog_cache_disk_use 值比較大的時候而且Binlog_cache_use也比較大的時候,我們可以考慮適當的調高 binlog_cache_size 對應的值


進一步分析:
我們這裡可以看到Binlog_cache_disk_use已經是1.27M,而且Binlog_cache_use值為264437761表示已經執行了2億多次了,而且這2個值一直在變大,就表名,binlog_cache_size遠遠不夠用,所以這裡就可以提高binlog_cache_size的值了。

MySQL:(none) 13:40:08> set global binlog_cache_size=8388608;
Query OK, 0 rows affected (0.00 sec)

MySQL:(none) 13:40:22> 
  • 1
  • 2
  • 3
  • 4


引申下max_binlog_cache_size:

max_binlog_cache_size 表示的是binlog 能夠使用的最大cache 記憶體大小,當我們執行多語句事務的時候 所有session的使用的記憶體超過max_binlog_cache_size的值時,就會報錯:“Multi-statement transaction required more than ‘max_binlog_cache_size’ bytes ofstorage”,設定太大的話,會比較消耗記憶體資源;設定太小又會使用到臨時檔案即disk