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