[转载]评估某个SQL回滚需要的耗时

2023-05-01 09:59:58 浏览数 (2)

原文地址  https://mydbops.wordpress.com/2022/02/07/estimating-time-for-rollback-operation/

回滚是一种操作,它将事务的当前状态更改为以前的状态。如果我们想回滚任何未提交的事务,通常需要undo logs ,并且它在隔离中起着重要作用。

对于事务期间所做的任何更改,都必须优先存储,因为如果我们选择回滚事务,这些更改是必需的。

数据修改完成后,将在撤消日志中创建条目。如果事务使用SQL命令修改数据,它将为每个操作创建离散的undo logs 。一旦事务被提交,MySQL就可以自由地清除在该事务中创建的 undo logs。

通常,回滚过程将比原始操作花费更多的时间。因为这是一个单线程进程。

案例:让我们考虑一个有1亿条记录的表sbtest1。我将根据id<=3000000的条件删除3000万条记录。因此,在这中间,我强行终止了删除操作。

手工处理的方法:

代码语言:javascript复制
mysql> show processlist;
 —- —————– ———– ——— ——— —— ———————— —————————————- 
| Id | User            | Host      | db      | Command | Time | State                  | Info                                   |
 —- —————– ———– ——— ——— —— ———————— —————————————- 
|  5 | event_scheduler | localhost | NULL    | Daemon  | 7306 | Waiting on empty queue | NULL                                   |
| 17 | root            | localhost | sb_test | Killed  |  704 | query end              | delete from sbtest1 where id<=30000000 |
| 18 | root            | localhost | sb_test | Sleep   |  626 |                        | NULL                                   |
| 19 | root            | localhost | NULL    | Query   |    0 | init                   | show processlist                       |
 —- —————– ———– ——— ——— —— ———————— —————————————- 
4 rows in set (0.00 sec)

其中id 为17的是正在回滚的事务会话。

代码语言:javascript复制
mysql> pager grep -e 'trx_mysql_thread_id: 17' -e trx_rows_modified

mysql> select * from information_schema.innodb_trxG select sleep(60); select * from information_schema.innodb_trxG
         trx_rows_modified: 0
       trx_mysql_thread_id: 17
         trx_rows_modified: 18460230
2 rows in set (0.26 sec)


1 row in set (1 min 0.31 sec)


       trx_mysql_thread_id: 17
         trx_rows_modified: 17169927
1 row in set (0.09 sec)


mysql> n


mysql> select SEC_TO_TIME(round((17169927*60)/(18460230–17169927))) as 'Estimation Time of Rollback';
 —————————– 
| Estimation Time of Rollback |
 —————————– 
| 00:13:18                     |
 —————————– 
1 row in set (0.18 sec)

也可以写个存储过程来做:

代码语言:javascript复制
use mysql;  -- 随便切到一个库里也行

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 ;

执行效果,如下:

代码语言:javascript复制
-- 参数1 是处于终止状态中的processlist id,参数2 是评估的时间间隔

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)

使用上面创建的函数,我们可以轻松估计回滚操作的大致时间为 06 分 09 秒。

0 人点赞