在MySQL的慢查詢日志中出現只有commit,但是沒有任何其它SQL的這種現象到底是一個什么情況呢?如下截圖所示(沒有優化前的一個Zabbix數據庫)
其實在慢查詢日志中出現commit,就是因為事務提交(commit)的時間過長。至於為什么commit的時間過長,可能有下面一些原因:
1:磁盤IO過載時或者發生故障的時候,因此在事務完成時進行刷新(flush)需要很長時間。
2:二進制日志輪換(Rotate)時,在二進制日志輪換完成之前,無法提交其他任何事務。這個會引起事務提交出現短暫的停頓/卡頓。尤其當二進制日志過大或者IO性能差的時候,這個停頓可能更長。導致commit的時間超過參數long_query_time的值。從而commit語句出現在慢查詢日志。
3: MySQL的系統參數innodb_flush_log_at_trx_commit、sync_binlog、max_binlog_size的設置可能會引起這種現象。但是注意,並不是說設這些參數的某個設置就一定會引起這個現象。而是說在某種取值下,在磁盤IO過載,業務暴增等一系列的綜合因素影響下,會增加這種現象出現的概率。
舉個例子,將MySQL配置為sync_binlog = 0的情況下,這可能導致操作系統緩存整個二進制日志,甚至使用最快的磁盤。默認情況下,最大二進制日志大小為1G,如果所有日志均已緩存,則需要一些時間才能寫出。 在這種情況下,沒有其他事務可以提交。那么就可能出現commit耗時變長的情況。而如果將max_binlog_size設置小一些,那么就緩解這種情況。
4:事務過大,導致事務提交的時候,需要等候的時間過長,尤其是發生二進制日志輪換時。
下面我們構造一個這樣的例子,准備測試環境,如下所示,當然這個實驗受數據量,表的結構,還有MySQL的參數等很多因素的影響。下面實驗僅僅說明一個超大的事務可能出現這種現象。在你的測試環境中,根據實驗情況進行調整。
create table test(id int auto_increment primary key, name varchar(32));
delimiter &&
drop procedure if exists prc_insert;
create procedure prc_insert(in row_cnt int)
begin
declare i int;
set i=1;
while i < row_cnt do
insert into test(name)
SELECT CONCAT('KERRY', cast(i as char));
set i = i+1;
end while;
end &&
delimiter ;
准備好上面的表以及存儲過程后,然后我們在下面事務中執行下面腳本
mysql> set session autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> call prc_insert(10000000);
Query OK, 1 row affected (7 min 1.31 sec)
mysql> commit;
Query OK, 0 rows affected (32.24 sec)
mysql>
在上面SQL執行的時候,使用下面腳本一直觀察慢查詢日志,就會發現它會出現只有commit的這種現象。如下截圖所示
# tail -60f /mysql_data/mysql/KerryDB-slow.log
對於這種現象,那么有什么解決方案嗎? 像我維護的zabbix系統,通過使用分區表方案后,與那些大表相關的SQL性能變好,那么就很少出現這種現象。其實除了優化SQL外,還有一些解決方案,參考下面官方文檔。
Commit Takes Too Long Time (Doc ID 1925395.1)
In this Document
APPLIES TO: MySQL Server - Version 4.1 and later Following symptoms may be observed:
Disk is overloaded or malfunctioning, so flushing on transaction completion takes long time. - Address problem to Hardware Admins to confirm whether disk partition with InnoDB logs is overloaded or malfunctioning. - Reduce load from physical disk partition, e.g. introducing fast dedicated physical disk for InnoDB logs or moving tmpdir to dedicated disk if it causes high load, etc. - Consider reducing durability of data by implementing less safe configuration for innodb_flush_log_at_trx_commit and sync_binlog if that suits your system (i.e. data loss is not critical or will not happen because of hardware/OS configuration: e.g. if you may rely on your OS to always shutdown properly). In case if problem happens with sync_binlog=0, consider reducing max_binlog_size to decrease amount of flushed data during binlog rotation. |
參考資料:
https://support.oracle.com/epmos/faces/DocumentDisplay?_afrLoop=430623618290439&parent=EXTERNAL_SEARCH&sourceId=PROBLEM&id=1925395.1&_afrWindowMode=0&_adf.ctrl-state=1008ex2pna_4