Подтвердить что ты не робот

Есть ли способ увидеть прогресс инструкции ALTER TABLE в MySQL?

Например, я выпустил инструкцию ALTER TABLE для создания индекса в поле MEDIUMTEXT в таблице InnoDB с 134k строками, где размер индекса составлял 255 байт, а средний размер данных в поле - 30k. Эта команда работает в течение последних 15 минут (и это единственное, что работает в базе данных). Есть ли способ определить, будет ли он заканчиваться ближе к 5 минутам, 5 часам или 5 дням?

4b9b3361

Ответ 1

Это довольно распространенный запрос, по-видимому, запрошенный еще в 2005 году на bugs.mysql.com. Он уже существует в Oracle и указан как полезный, но " это не простая вещь, поэтому не ожидайте, что это будет в скором времени ". Хотя это было в 2005 году:)

Тем не менее, парень, который задал оригинальный вопрос, позже выпустил патч для MySQL 5.0, backported to 4.1, который может помочь вам.

Ответ 2

Мне удалось выполнить эти 2 запроса и выяснить, сколько строк осталось перемещать.

select count(*) from `myoriginalrable`;
select count(*) from `#sql-1e8_11ae5`;

это было более полезным, чем сравнение размера файла на диске, поскольку изменение с myisam на innodb и т.д. меняет размер строки.

Ответ 3

В случае таблиц 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). См:

http://kb.askmonty.org/en/progress-reporting/

Ответ 4

Я сделал запрос, который оценивает время завершения команды alter в таблице innodb. Вы должны запустить его как минимум дважды в одном сеансе, так как он сравнивает статистику от последовательных прогонов, чтобы сделать оценку. Не забудьте заменить <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)[email protected]),
    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:[email protected],
    @p_modified:[email protected],
    @p_beginsd:[email protected]
) sq;

Ответ 5

pt-online-schema-change от Percona показывает оставшуюся временную оценку. По умолчанию он выдает оставшуюся оценку времени и процент прогона каждые 30 секунд.

Он также имеет дополнительные функции по сравнению с просто выполнением команды ALTER.

http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html

Ответ 6

Запустите ls -laShr/var/lib/mysql | sort -h 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 отсортирует файлы по размеру, поэтому оба файла будут в нижней части списка файлов, если это большая таблица и вы долго ждали.

Ответ 7

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

Ответ 8

если кто-то хочет решения 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

Выводы: на это нужно время, много времени.

просто убедитесь, что есть баран бесплатно. и свободное пространство. как 50% памяти не используется mysql.

низкая скорость плунжера заставляет всю систему работать очень низко