it-swarm-eu.dev

Comment trouver et réparer des tables MySQL fragmentées

J'ai utilisé MySQLTuner qui a souligné que certaines tables étaient fragmentées. j'ai utilisé

mysqlcheck --optimize -A

pour optimiser toutes les tables. Il a corrigé quelques tables mais MySQLTuner trouve toujours 19 tables fragmentées. comment savoir quelles tables ont besoin d'être défragmentées? Peut-être qu'OPTIMIZE TABLE fonctionnera là où mysqlcheck n'a pas fonctionné? Ou quoi d'autre devrais-je essayer?

27
curiouscat

la réponse courte:

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 réponse "Vous devez savoir"

tout d'abord, vous devez comprendre que les tables Mysql sont fragmentées lorsqu'une ligne est mise à jour, c'est donc une situation normale. Lorsqu'une table est créée, disons importée à l'aide d'un vidage avec des données, toutes les lignes sont stockées sans fragmentation dans de nombreuses pages de taille fixe. Lorsque vous mettez à jour une ligne de longueur variable, la page contenant cette ligne est divisée en deux pages ou plus pour stocker les modifications et ces deux nouvelles pages (ou plus) contiennent des espaces vides remplissant l'espace inutilisé.

Cela n'affecte pas les performances, sauf bien sûr si la fragmentation augmente trop. Ce qui est trop de fragmentation, voyons bien la requête que vous recherchez:

  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 et INDEX_LENGTH sont l'espace utilisé par vos données et index et DATA_FREE est la quantité totale d'octets inutilisés dans toutes les pages de table (fragmentation).

Voici un exemple d'une vraie table de production

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

Dans ce cas, nous avons une table utilisant (896 + 316) = 1212 Mo, et avons des données sur un espace libre de 5 Mo. Cela signifie un "rapport de fragmentation" de:

5/1212 = 0.0041

... Ce qui est un "taux de fragmentation" vraiment faible.

J'ai travaillé avec des tables avec un ratio proche de 0,2 (soit 20% des espaces vides) et je ne remarque jamais de ralentissement des requêtes, même si j'optimise la table, les performances sont les mêmes. Mais appliquer une table d'optimisation sur une table de 800 Mo prend beaucoup de temps et bloque la table pendant plusieurs minutes, ce qui est impraticable en production.

Donc, si vous considérez ce que vous gagnez en performances et le temps perdu à optimiser une table, je préfère NE PAS OPTIMISER.

Si vous pensez que c'est mieux pour le stockage, voyez votre ratio et voyez combien d'espace pouvez-vous économiser en optimisant. Ce n'est généralement pas trop, donc je préfère NE PAS OPTIMISER.

Et si vous optimisez, la prochaine mise à jour créera des espaces vides en divisant une page en deux ou plus. Mais il est plus rapide de mettre à jour une table fragmentée qu'une table non fragmentée, car si la table est fragmentée, une mise à jour sur une ligne ne divisera pas nécessairement une page.

J'espère que ceci vous aide.

38
Felipe Rojas

Juste pour ajouter à la réponse de Felipe-Rojas vous pouvez calculer le taux de fragmentation dans le cadre de la requête:

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 un tableau est fragmenté à un faible pourcentage (moins de 5%?), Vous pouvez probablement le laisser seul.

Tout ce qui est plus grand et vous devrez évaluer en fonction de votre utilisation de la base de données, du verrouillage des tables, etc., à quel point il est important de défragmenter la table.

15
sysadmiral

Optimiser la table résoudra en effet le problème que vous rencontrez.

Si vous n'avez que quelques bases de données, vous pouvez utiliser PHPMyAdmin pour parcourir toutes vos bases de données. Sélectionnez les tables avec des frais généraux, puis sélectionnez pour optimiser.

Si vous avez beaucoup de bases de données, une autre méthode serait probablement préférable.

J'utilise la configuration de script suivante PHP dans cron pour exécuter toutes les heures.

$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();
2
Daemon of Chaos

Je suis tombé sur cette page et j'ai trouvé les requêtes de Felipe-Rojas et sysadmiral très utiles. Mais dans mon cas, j'exécutais la requête dans phpMyAdmin de WHM et obtenir uniquement TABLE_NAME n'était pas aussi utile car la base de données n'était pas répertoriée et plusieurs bases de données ont les mêmes noms de table. Donc, en ajoutant simplement TABLE_SCHEMA fournira également cette colonne.

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

Affiche DB

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

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

Pour "corriger", j'ai utilisé le lien de la table de défragmentation dans phpMyAdmin pour chacune des tables qui ont abouti à un "frag_ratio" élevé pour lequel phpMyAdmin s'exécute:

ALTER TABLE `table_name` ENGINE = InnoDB;
2
Chris

Une table utilisant le moteur InnoDB de MySQL n'a pratiquement jamais besoin d'être OPTIMIZEd.

La valeur de Data_free de l'un ou l'autre information_schema.tables ou SHOW TABLE STATUS est très souvent différent de zéro, même si vous pensez avoir fait tout ce que vous pouvez faire pour défragmenter vos tables. De plus, cette métrique n'est qu'une des plusieurs fragmentations qui peuvent et se produisent. (En outre, l'espace perdu dans les blocs, les listes d'annulation, les BTrees d'index vs les BTrees de données, etc., etc.

Et innodb_file_per_table complique l'utilisation de Data_free. Si la table est en ibdata1, puis Data_free fait référence à tout l'espace disque logique; un nombre plutôt inutile. Si la table est dans son propre .ibd fichier, il est susceptible de représenter quelques Mo ou quelques pour cent de la taille de la table, la valeur la plus élevée étant retenue.

Ce n'est que si vous avez supprimé lots de lignes et que vous n'avez pas l'intention de remplir la table, peut-être cela vaut la peine d'être exécuté OPTIMIZE TABLE.

PARTITIONs affiche également une quantité inquiétante de Data_free, puisque chaque partition affiche généralement 4-7 Mo "libre". Et cela ne disparaîtra pas.

Pourquoi défragmenter?

  • Pour retourner de l'espace au système d'exploitation? Eh bien, vous pourriez y parvenir brièvement si vous aviez innodb_file_per_table=1. Mais lorsque vous ajoutez des lignes, vous les récupérez du système d'exploitation.
  • Pour accélérer l'accès? Oublie. La disposition des blocs sur le disque est relativement aléatoire, et ce depuis les dernières décennies. Il y a un demi-siècle, il était quelque peu important de réorganiser les blocs.
  • Pour rééquilibrer BTrees? Donc? Ils redeviendront rapidement déséquilibrés. L'état stable pour les BTrees qui sont insérés de manière aléatoire dans est de 69%. Et cela n'est même pas pris en compte dans Data_free.
  • MySQLTuner le dit? Ce produit doit refroidir.

Une note d'histoire. Lorsque j'aidais les administrateurs de bases de données avec principalement des tables MyISAM, j'ai découvert peut-être 2 des 1000 tables aidées par un mensuelOPTIMIZE. Depuis lors, j'ai travaillé avec des milliers de tables InnoDB, mais je n'ai pas encore trouvé de problème de performance qui était susceptible d'être résolu par OPTIMIZE. (Bien sûr, il y a eu des problèmes d'espace disque pour lesquels OPTIMIZE pourrait aider, mais cela devient délicat - généralement le DBA n'a pas assez d'espace disque pour exécuter OPTIMIZE!)

1
Rick James