2008-09-04 8 views
24

Por ejemplo, emití una instrucción ALTER TABLE para crear un índice en un campo MEDIUMTEXT en una tabla InnoDB que tiene 134 filas donde el tamaño del índice era 255 bytes y el tamaño promedio de los datos en el campo es 30k. Este comando se ha estado ejecutando durante los últimos 15 minutos aproximadamente (y es lo único que se ejecuta en la base de datos). ¿Hay alguna manera de determinar si va a terminar en 5 minutos, 5 horas o 5 días más o menos?¿Hay alguna forma de ver el progreso de una instrucción ALTER TABLE en MySQL?

Respuesta

18

Pude realizar estas 2 consultas y averiguar cuántas filas quedan por mover.

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

Esto fue mucho más útil que comparar el tamaño del archivo en el disco, porque el cambio de myisam a InnoDB etc cambia el tamaño de la fila.

+3

¿Cómo se obtiene el nombre de la tabla temporal que crea el comando alter? – fixxxer

+2

El nombre de la tabla temporal se puede encontrar en el sistema de archivos con el resto de las tablas. – carillonator

+0

mejor respuesta maldita de todos ellos, ¡gracias! – Enerccio

11

En el caso de las tablas InnoDB, se puede usar SHOW ENGINE INNODB STATUS para encontrar la transacción haciendo ALTER TABLE y verificar cuántos bloqueos de fila tiene el TX. Este es el número de filas procesadas. Se explica en detalle aquí:

http://gabrielcain.com/blog/2009/08/05/mysql-alter-table-and-how-to-observe-progress/

también MariaDB 5.3 y posteriores tiene la función de informar sobre el progreso de algunas operaciones (incluyendo ALTER TABLE). Ver:

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

+0

MariaDB 5.3+ y Percona Server – Go4It

+1

FYI esa publicación de blog indica que el truco 'SHOW ENGINE INNODB STATUS' solo funciona para MySQL 5.0. – cbmanica

3

Hice una consulta que calcula el tiempo para terminar una orden de modificación sobre una tabla InnoDB. Debes ejecutarlo al menos dos veces en la misma sesión, ya que compara las estadísticas de las ejecuciones consecutivas para realizar la estimación. No olvides cambiar <tableName> con el nombre de la tabla correcta en la cuarta línea. Te da dos estimaciones. La estimación local usa solo datos entre ejecuciones, mientras que la estimación global usa todo el tiempo de transacción.

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; 
Cuestiones relacionadas