Cómo encontrar y arreglar tablas MySQL fragmentadas

27

Usé MySQLTuner que señaló que algunas tablas estaban fragmentadas. solía

mysqlcheck --optimize -A

para optimizar todas las tablas. Se arreglaron algunas tablas, pero MySQLTuner todavía encuentra 19 tablas fragmentadas. ¿Cómo puedo ver qué tablas necesitan desfragmentar? ¿Quizás OPTIMIZE TABLE funcionará donde mysqlcheck no funcionó? ¿O qué más debo probar?

curioso
fuente
1
Tengo un problema similar. Estoy configurando una nueva base de datos con MySQL 5.5 y ciertas tablas de InnoDB nunca se fragmentan. Me pregunto si la comprobación de Data_free (que se muestra en la respuesta de KayakJim) es incorrecta con las tablas de InnoDB.
docwhat

Respuestas:

38

la respuesta corta:

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

La respuesta "Debe saber"

En primer lugar, debe comprender que las tablas Mysql se fragmentan cuando se actualiza una fila, por lo que es una situación normal. Cuando se crea una tabla, digamos importada usando un volcado con datos, todas las filas se almacenan sin fragmentación en muchas páginas de tamaño fijo. Cuando actualiza una fila de longitud variable, la página que contiene esta fila se divide en dos o más páginas para almacenar los cambios, y estas nuevas dos (o más) páginas contienen espacios en blanco que llenan el espacio no utilizado.

Esto no afecta el rendimiento, a menos que, por supuesto, la fragmentación crezca demasiado. ¿Qué es demasiada fragmentación? Bueno, veamos la consulta que está buscando:

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH e INDEX_LENGTH son el espacio que usan sus datos e índices, y DATA_FREE es la cantidad total de bytes no utilizados en todas las páginas de la tabla (fragmentación).

Aquí hay un ejemplo de una tabla de producción real

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

En este caso tenemos una tabla que usa (896 + 316) = 1212 MB, y tenemos datos en un espacio libre de 5 MB. Esto significa una "relación de fragmentación" de:

5/1212 = 0.0041

... que es una "relación de fragmentación" realmente baja.

He estado trabajando con tablas con una proporción cercana a 0.2 (es decir, el 20% de los espacios en blanco) y nunca noto una desaceleración en las consultas, incluso si optimizo la tabla, el rendimiento es el mismo. Pero aplicar una tabla de optimización en una tabla de 800 MB lleva mucho tiempo y bloquea la tabla durante varios minutos, lo que no es posible en la producción.

Entonces, si considera lo que gana en rendimiento y el tiempo perdido en optimizar una tabla, prefiero NO OPTIMIZAR.

Si cree que es mejor para el almacenamiento, vea su relación y vea cuánto espacio puede ahorrar al optimizar. Por lo general, no es demasiado, así que prefiero NO OPTIMIZAR.

Y si optimiza, la próxima actualización creará espacios en blanco al dividir una página en dos o más. Pero es más rápido actualizar una tabla fragmentada que una no fragmentada, porque si la tabla está fragmentada, una actualización en una fila no necesariamente dividirá una página.

Espero que esto te ayude.

Felipe Rojas
fuente
1
Aunque esta es una respuesta de hace varios años, pensé en señalar que data_free es una estadística para todo el espacio de tabla, no para la tabla respectiva. Si almacena varias tablas juntas en un espacio de tabla, data_free puede inducirlo a error a creer que la tabla necesita desfragmentación, cuando solo significa que hay extensiones libres en el espacio de tabla. Ejecutar la tabla de optimización no reducirá las extensiones libres. Desfragmentar la tabla puede incluso aumentar las extensiones libres.
Bill Karwin
14

Solo para agregar a la respuesta de Felipe-Rojas , puede calcular la proporción de fragmentos como parte de la consulta:

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

Si una tabla está fragmentada en un pequeño porcentaje (¿menos del 5%?), Entonces probablemente pueda dejarla sola.

Cualquier cosa más grande y tendrá que evaluar en función de su uso de db, tablas de bloqueo, etc., lo importante que es desfragmentar la tabla.

sysadmiral
fuente
2

Optimizar tabla resolverá el problema que está teniendo.

Si solo tiene unas pocas bases de datos, puede usar PHPMyAdmin para revisar todas sus bases de datos. Seleccione las tablas con gastos generales y luego seleccione para optimizar.

Si tiene muchas bases de datos, probablemente sería preferible otro método.

Utilizo la siguiente configuración de script PHP en cron para ejecutar cada hora.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();
Demonio del caos
fuente
3
Estoy bastante seguro de que mysqlcheck --optimize -Aes lo mismo que el SQLOPTIMIZE TABLE <tablename>;
docwhat
2

Encontré esta página y encontré que las consultas de Felipe-Rojas y sysadmiral fueron muy útiles. Pero en mi caso, estaba ejecutando la consulta en phpMyAdmin de WHM y obtener solo TABLE_NAME no fue tan útil ya que la base de datos no estaba en la lista, y varias bases de datos tienen los mismos nombres de tabla. Entonces, simplemente agregar TABLE_SCHEMAtambién proporcionará esa columna.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

Muestra DB

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

Para "arreglar", utilicé el enlace de tabla Desfragmentar en phpMyAdmin para cada una de las tablas que resultó en una "frag_ratio" alta para la que se ejecuta phpMyAdmin:

ALTER TABLE `table_name` ENGINE = InnoDB;
Chris
fuente
0

Una tabla que usa el motor InnoDB de MySQL esencialmente nunca necesita serlo OPTIMIZEd.

El valor de Data_freecualquiera information_schema.tableso SHOW TABLE STATUSmuy a menudo no es cero, incluso cuando cree que ha hecho todo lo que puede hacer para desfragmentar su (s) tabla (s). Además, esa métrica es solo una de varias fragmentaciones que pueden ocurrir y ocurren. (También, espacio desperdiciado en bloques, listas de deshacer, indexar BTrees vs data BTrees, etc., etc.

Y innodb_file_per_tablecomplica el uso de Data_free. Si la tabla está adentro ibdata1, se Data_freerefiere a todo el espacio de tabla; Un número bastante inútil. Si la tabla está en su propio .ibdarchivo, es probable que tenga unos pocos MB o un pequeño porcentaje del tamaño de la tabla, lo que sea mayor.

Solo si ha eliminado muchas filas y no tiene la intención de volver a llenar la tabla, podría valer la pena ejecutarla OPTIMIZE TABLE.

PARTITIONstambién muestran una cantidad inquietante de Data_free, ya que cada partición generalmente muestra 4-7MB "gratis". Y esto no desaparecerá.

¿Por qué desfragmentar?

  • Para devolver espacio al sistema operativo? Bueno, podrías lograr esto brevemente si lo hubieras hecho innodb_file_per_table=1. Pero a medida que agrega filas, lo recuperará del sistema operativo.
  • Para acelerar el acceso? Olvídalo. El diseño de los bloques en el disco es relativamente aleatorio, y lo ha sido durante las últimas décadas. Hace medio siglo, era algo importante reorganizar los bloques.
  • Para reequilibrar BTrees? ¿Asi que? Pronto volverán a estar desequilibrados. El estado estacionario para BTrees que se insertan aleatoriamente es del 69%. Y eso ni siquiera se tiene en cuenta Data_free.
  • MySQLTuner dice que? Ese producto necesita enfriarse.

Una nota de historia. Cuando estaba ayudando a los DBA con tablas principalmente MyISAM, descubrí quizás 2 de cada 1000 tablas que recibían ayuda mensual OPTIMIZE . Desde entonces, he trabajado con miles de tablas de InnoDB, todavía he encontrado un problema de rendimiento que probablemente podría ser ayudado OPTIMIZE. (Claro, ha habido problemas de espacio en el disco que OPTIMIZEpodrían ayudar, pero eso se vuelve complicado, ¡por lo general, el DBA no tiene suficiente espacio en el disco para ejecutarse OPTIMIZE!)

Rick James
fuente