MySQL Estimate of the duration of a rollback operation(估算rollback事务回滚剩余时间)
很久以前记录过一篇 Oracle Estimate of the duration of a rollback operation (估算rollback事务回滚剩余时间) ,oracle的大事务cancel或kill后的回滚操作,rollback所花费的时间通常比原来的操作还要长,而且在回滚完成前有可能会堵塞其它事务,在PostgreSQL中因为没有使用undo而是多版本,所以忽略rollback的时间,这是PG的强项,但是在MySQL中和oracle一样同样存在回滚问题,这里简单记录如何估算MySQL中的事务回滚时间。
删除一个大表中的记录。
mysql> show processlist; +----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+ | 16 | root | localhost | anbob | Query | 0 | init | show processlist | | 18 | root | localhost | anbob | Query | 669 | updating | delete from anbo_t1 where id<=50000000 | +----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+ 3 rows in set (0.01 sec) mysql> kill 18; Query OK, 0 rows affected (0.26 sec)
查看进程状态
mysql> show processlist;
+----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+
| 18 | root | localhost | anbob | Killed | 704 | query end | delete from anbo_t1 where id<=50000000 |
| 19 | root | localhost | NULL | Query | 0 | init | show processlist |
+----+-----------------+-----------+---------+---------+------+------------------------+----------------------------------------+
INFORMATION_SCHEMA.INNODB_TRX Table的记录了当前事务修改行数,可以多次查询根据差值估算时间,rollback时该值会逐渐减少,直到0。
TRX_ROWS_MODIFIED
The number of modified and inserted rows in this transaction.
持续跟踪TRX_ROWS_MODIFIED
mysql> pager grep -e "trx_mysql_thread_id: 18" -e trx_rows_modified PAGER set to 'grep -e "trx_mysql_thread_id: 18" -e trx_rows_modified' mysql> select * from information_schema.innodb_trx\G select sleep(60); select * from information_schema.innodb_trx\G trx_rows_modified: 0 trx_mysql_thread_id: 18 trx_rows_modified: 19010230 2 rows in set (0.26 sec) 1 row in set (1 min 0.31 sec) trx_mysql_thread_id: 17 trx_rows_modified: 18039927 1 row in set (0.09 sec) mysql> \n PAGER set to stdout mysql> select SEC_TO_TIME(round((18039927/(19010230-18039927)*60))) as 'Estimation Time of Rollback'; +-----------------------------+ | Estimation Time of Rollback | +-----------------------------+ | 00:18:36 | +-----------------------------+
Note:
估算完成回滚操作还需要18分36秒。
mydbops上有一个好的function
DELIMITER $$ CREATE FUNCTION RollbackTimeCalc(processID INT, timeInterval INT) RETURNS VARCHAR(225) DETERMINISTIC BEGIN DECLARE RollbackModifiedBeforeInterval INT; DECLARE RollbackModifiedAfterInterval INT; DECLARE RollbackPendingRows INT; DECLARE Result varchar(20); SELECT trx_rows_modified INTO RollbackModifiedBeforeInterval from information_schema.innodb_trx where trx_mysql_thread_id = processID and trx_state = 'ROLLING BACK'; do sleep(timeInterval); SELECT trx_rows_modified INTO RollbackModifiedAfterInterval from information_schema.innodb_trx where trx_mysql_thread_id = processID and trx_state = 'ROLLING BACK'; set Result=SEC_TO_TIME(round((RollbackModifiedAfterInterval*timeInterval)/(RollbackModifiedBeforeInterval-RollbackModifiedAfterInterval))); SELECT trx_rows_modified INTO RollbackPendingRows from information_schema.innodb_trx where trx_mysql_thread_id = processID and trx_state = 'ROLLING BACK'; RETURN(CONCAT('Estimation Time of Rollback : ', Result, ' Pending rows to rollback ', RollbackPendingRows)); END$$ DELIMITER ;
我们必须向函数传递两个参数
RollbackTimeCalc(x,y);
x 是被终止事务的进程列表 ID,
y 是撤消日志条目的时间间隔
e.g.
mysql> select RollbackTimeCalc(18,5); +--------------------------------------------------------------------------+ | RollbackTimeCalc(18,5) | +--------------------------------------------------------------------------+ | Estimation Time of Rollback : 00:06:09 Pending rows to rollback 10341861 | +--------------------------------------------------------------------------+ 1 row in set (5.37 sec)
建议还是把大事务拆成几份,简化MySQL的使用,另外对数据库进行重大更改,最好设置 autocommit=0。并且不要忘记在事务结束时添加 autocommit=1。
对不起,这篇文章暂时关闭评论。