例如,我发出了一个 ALTER TABLE 语句来为 InnoDB 表中的 MEDIUMTEXT 字段创建索引,该表有 134k 行,其中索引的大小为 255 字节,字段中数据的平均大小为 30k。该命令已经运行了 15 分钟左右(并且是唯一在数据库上运行的命令)。我有什么方法可以确定它是否会在接近 5 分钟、5 小时或 5 天后完成?
9 回答
我能够执行这 2 个查询并计算出还有多少行需要移动。
select count(*) from `myoriginalrable`;
select count(*) from `#sql-1e8_11ae5`;
这比比较磁盘上的文件大小更有帮助,因为从 myisam 更改为 innodb 等会改变行大小。
对于 InnoDB 表,可以使用SHOW ENGINE INNODB STATUS
查找执行 ALTER TABLE 的事务并检查 TX 持有多少行锁。这是处理的行数。这里详细解释:
http://gabrielcain.com/blog/2009/08/05/mysql-alter-table-and-how-to-observe-progress/
MariaDB 5.3 及更高版本还具有报告某些操作(包括 ALTER TABLE)进度的功能。看:
这显然是一个很常见的请求——早在 2005 年就在bugs.mysql.com上提出请求。它已经存在于 Oracle 中,并且被列为有用,但“这不是一件简单的事情,所以不要指望它很快就会实现”。. 虽然那是 2005 年 :)
也就是说,提出原始问题的小伙子后来发布了MySQL 5.0 的补丁,向后移植到 4.1,这可能会对您有所帮助。
我做了一个查询,估计在 innodb 表上完成一个 alter 命令的时间。您必须在同一会话中至少运行两次,因为它会比较连续运行的统计数据以进行估计。不要忘记在第四行将<tableName>更改为正确的表名。它给你两个估计。局部估计仅使用运行之间的数据,而全局估计使用整个事务时间。
select
beginsd, now(), qRuns, qTime, tName, trxStarted, trxTime, `rows`, modified, locked, hoursLeftL, estimatedEndL, modifiedPerSecL, avgRows, estimatedEndG, modifiedPerSecG, hoursLeftG
from (
select
(@tname:='<table>') tName,
@beginsd:=sysdate() beginsd,
@trxStarted:=(select trx_started from information_schema.innodb_trx where trx_query like concat('alter table %', @tname, '%')) trxStarted,
@trxTime:=timediff(@beginsd, @trxStarted) trxTime,
@rows:=(select table_rows from information_schema.tables where table_name like @tname) `rows`,
@runs:=(ifnull(@runs, 0)+1) qRuns,
@rowsSum:=(ifnull(@rowsSum, 0)+@rows),
round(@avgRows:=(@rowsSum / @runs)) avgRows,
@modified:=(select trx_rows_modified from information_schema.innodb_trx where trx_query like concat('alter table %', @tname, '%')) modified,
@rowsLeftL:=(cast(@rows as signed) - cast(@modified as signed)) rowsLeftL,
round(@rowsLeftG:=(cast(@avgRows as signed) - cast(@modified as signed)), 2) rowsLeftG,
@locked:=(select trx_rows_locked from information_schema.innodb_trx where trx_query like concat('alter table %', @tname, '%')) locked,
@endsd:=sysdate() endsd,
--
time_to_sec(timediff(@endsd, @beginsd)) qTime,
@modifiedInc:=(cast(@modified as signed) - cast(@p_modified as signed)) modifiedInc,
@timeInc:=time_to_sec(timediff(@beginsd, @p_beginsd)) timeInc,
round(@modifiedPerSecL:=(@modifiedInc/@timeInc)) modifiedPerSecL,
round(@modifiedPerSecG:=(@modified/time_to_sec(@trxTime))) modifiedPerSecG,
round(@minutesLeftL := (@rowsLeftL / @modifiedPerSecL / 60)) minutesLeftL,
round(@minutesLeftG := (@rowsLeftG / @modifiedPerSecG / 60)) minutesLeftG,
round(@hoursLeftL := (@minutesLeftL / 60), 2) hoursLeftL,
round(@hoursLeftG := (@minutesLeftG / 60), 2) hoursLeftG,
(@beginsd + INTERVAL @minutesLeftL MINUTE) estimatedEndL,
(@beginsd + INTERVAL @minutesLeftG MINUTE) estimatedEndG,
--
@p_rows:=@rows,
@p_modified:=@modified,
@p_beginsd:=@beginsd
) sq;
非常老的问题,但至少 mysql 5.7 对此有一个正确的答案
https://dev.mysql.com/doc/refman/5.7/en/monitor-alter-table-performance-schema.html
在本质上...
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES'
WHERE NAME LIKE 'stage/innodb/alter%';
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE '%stages%';
...运行更改表...
SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
FROM performance_schema.events_stages_current;
+------------------------------------------------------+----------------+----------------+
| EVENT_NAME | WORK_COMPLETED | WORK_ESTIMATED |
+------------------------------------------------------+----------------+----------------+
| stage/innodb/alter table (read PK and internal sort) | 280 | 1245 |
+------------------------------------------------------+----------------+----------------+
1 row in set (0.01 sec)
运行ls -laShr /var/lib/mysql | sort -h
,你会在 mysql 文件夹中看到类似这样的文件:
-rw-r----- 1 mysql mysql 3.3G Feb 9 13:21 sql-#2088_10fa.ibd
-rw-r----- 1 mysql mysql 10.2G Feb 9 13:21 posts.ibd
您可以看到原始表文件和临时目标表文件正在构建,具有人类可读的大小。通常它会随着时间线性增长,所以如果它是原始表的一半大小,它就是一半。该ls
命令将按大小对文件进行排序,因此如果这是一个大表并且您已经等待了一段时间,那么这两个文件都将位于文件列表的底部附近。
Percona 的 pt-online-schema-change 显示剩余时间估计。默认情况下,它每 30 秒打印一次剩余时间估计和进度百分比。
与单独运行 ALTER 命令相比,它还具有其他功能。
http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html
如果有人想要 bash 解决方案:(sql 不适合我)
cd /var/lib/mysql/mydb
TABLEFILE="MYTABLE.ibd"
TEMPFILE="\#*ibd"
ls -lah $TABLEFILE;
ls -lah $TEMPFILE; # make sure you have only one temp file or modify the above TEMPFILE
SIZE_TOTAL=$(stat -c %s $TABLEFILE);
# other ways to get 1st size and time
#SIZE1=1550781106; TIME1=1550781106;
#SIZE1=$(stat -c %s $TEMPFILE); TIME1=$(stat -c %Z $TEMPFILE); sleep 10;
SIZE1=0; TIME1=$(stat -c %X $TEMPFILE); # use file create time
echo "SIZE1=$TIME1; TIME1=$TIME1";
SIZE2=$(stat -c %s $TEMPFILE); TIME2=$(stat -c %Z $TEMPFILE);
DELTA_SIZE=$(( $SIZE2 - $SIZE1 ))
DELTA_TIME=$(( $TIME2 - $TIME1 ))
# debug last numbers should not be zero:
echo $SIZE1 $SIZE2 $SIZE_TOTAL $DELTA_SIZE;
echo $TIME1 $TIME2 $DELTA_TIME;
SIZE_PER_SECOND=$( awk "BEGIN {print $DELTA_SIZE / $DELTA_TIME }" );
SIZE_LEFT=$(($SIZE_TOTAL - $SIZE2));
TIME_LEFT_SECONDS=$( awk "BEGIN { print ( $SIZE_LEFT / $SIZE_PER_SECOND) }" );
TIME_LEFT_MINUTES=$( awk "BEGIN { print $TIME_LEFT_SECONDS /60 }" );
TIME_LEFT=$( awk "BEGIN { printf \"%d:%02d:%2d\", int($TIME_LEFT_MINUTES /60), int($TIME_LEFT_MINUTES % 60), int($TIME_LEFT_SECONDS % 60 ) }" );
echo "TIME_LEFT = $TIME_LEFT";
echo "SIZE_LEFT = $SIZE_LEFT" "MB=" $(( $SIZE_LEFT/1024/1024 )) ;
awk "BEGIN { if( $SIZE_TOTAL == $SIZE2 ) print \"mysql finished\" }" ;
free -h # check free memory, sometimes it is full and it makes it slow
结论:这需要时间,很多时间。
只要确保有 ram 空闲。和自由空间。像 50% 的内存没有被 mysql 使用。
低内存使整个系统工作非常低
Percona Server是 MySQL 的一个分支版本,具有一些增强功能,具有此功能。
您可以在 SHOW PROCESSLIST 中观察 ROWS_SENT 和 ROWS_EXAMINED 的额外列。例如,如果您的表有 1000000 行,并且您看到 ROWS_EXAMINED 为 650000,那么它已完成 65%。
请参阅http://www.percona.com/doc/percona-server/5.6/diagnostics/process_list.html