web-dev-qa-db-fra.com

Maintenance des index MySQL

J'ai fait beaucoup de recherches sur la façon de maintenir les index dans MySQL pour éviter la fragmentation et optimiser en quelque sorte l'exécution de certaines requêtes.

Je connais cette formule qui calcule le rapport entre l'espace maximum disponible pour une table VS l'espace utilisé par les données et les index.

Cependant, mes principales questions restent sans réponse. Cela est peut-être dû au fait que je connais la maintenance des index dans SQL Server, et j'ai tendance à penser que dans MySQL, cela devrait être en quelque sorte similaire.

Dans SQL Server, vous pouvez avoir plusieurs index et chacun d'entre eux peut avoir différents niveaux de fragmentation. Ensuite, vous pouvez en choisir un et effectuer une opération de "RÉORGANISATION" ou "RECONSTRUCTION" dans cet index particulier, sans affecter le reste.

À ma connaissance, il n'y a pas de "fragmentation de table" en tant que telle, et SQL Server ne fournit aucun outil pour corriger la "fragmentation de table". Il fournit des outils pour vérifier la fragmentation d'index (compris comme le rapport entre le nombre de pages utilisées par un index VS la plénitude de cette page et la contiguïté), ainsi que la fragmentation interne et externe.

Tout cela est assez simple à comprendre, du moins pour moi.

Maintenant, quand vient le tour de maintenir les index dans MySQL, il n'existe que le concept de "fragmentation de table, comme mentionné ci-dessus.

Une table dans MySQL peut avoir plusieurs index, mais quand je vérifie le 'ratio de fragmentation' avec cette fameuse formule, je ne vois pas la fragmentation de chaque index, mais la table dans son ensemble.

Quand je veux optimiser les index dans MySQL, je ne choisis pas un index particulier sur lequel opérer (comme dans SQL Server). Au lieu de cela, je fais une opération "OPTIMIZE" dans toute la table, ce qui affecte vraisemblablement tous les index.

Lorsque la table est optimisée dans MySQL, le rapport entre l'espace utilisé par data + index VS l'espace global est réduit, ce qui suggère une sorte de réorganisation physique dans le disque dur, ce qui se traduit par une réduction de l'espace physique. Cependant, la fragmentation d'index ne concerne pas seulement l'espace physique, mais la structure de l'arborescence qui a été modifiée au fil du temps en raison des insertions et des mises à jour.

Enfin, j'ai obtenu une table dans InnoDB/MySQL. Ce tableau contient 3 millions d'enregistrements, 105 colonnes et 55 index. Il est de 1,5 Go hors index, qui sont de 2,1 Go.

Cette table est frappée des milliers de fois par jour pour la mise à jour, l'insertion (nous ne supprimons pas les enregistrements).

Cette table a été créée des années auparavant et je sais avec certitude que personne ne tient à jour les index.

Je m'attendais à y trouver une énorme fragmentation, mais lorsque j'effectue le calcul de fragmentation comme prescrit

free_space / (data_length + index_length)

il s'avère que je n'ai qu'une fragmentation de 0,2%. À mon humble avis, c'est assez irréaliste.

Donc les grandes questions sont:

  1. Comment vérifier la fragmentation d'un index particulier dans MySQL, pas la table dans son ensemble
  2. OPTIMIZE TABLE corrige-t-il réellement la fragmentation interne/externe d'un index comme dans SQL Server?
  3. Lorsque j'optimise une table dans MySQL, est-ce qu'il reconstruit tous les index de la table?
  4. Est-il réaliste de penser que réduire l'espace physique d'un index (sans reconstruire l'arbre lui-même) se traduit réellement par de meilleures performances?
12
Nicolas

La fragmentation de l'indice est largement surestimée. Ne t'en fais pas.

InnoDB fusionne deux blocs adjacents, quelque peu vides, en tant que traitement naturel.

Des actions aléatoires sur un BTree le font naturellement graviter vers une moyenne de 69% de saturation. Bien sûr, ce n'est pas 100%, mais les frais généraux de "fixation" ne valent pas la peine.

SHOW TABLE STATUS Vous donne quelques métriques, mais elles sont imparfaites - "Data_free" inclut un certain espace "libre", mais pas un autre espace "libre".

Il y a de l'espace inutilisé dans chaque bloc; blocs libres de 16 Ko; "extensions" libres (morceaux de nMB); Lignes MVCC en attente d'être récoltées; les nœuds non foliaires ont leur propre fragmentation; etc.

Percona et Oracle ont différentes manières de voir la taille (nombre de blocs) d'un index. Je ne trouve aucun d'eux utile en raison de la définition limitée de "libre". Il semble que les blocs (16 Ko chacun) soient alloués en morceaux (plusieurs Mo), ce qui laisse penser qu'il existe toutes sortes de fragmentation. En réalité, il s'agit généralement de la plupart de ces morceaux de plusieurs Mo. Et OPTIMIZE TABLE Ne récupère pas nécessairement l'espace.

Si SQL Server utilise BTrees, il est faux de dire qu'il n'y a "pas de fragmentation". Pensez à ce qui se passe lors d'un "partage de blocs". Ou pensez aux frais généraux de la défragmentation continue. De toute façon, vous perdez.

Notez en outre qu'une table et un index sont des structures essentiellement identiques:

  • Arbre B +, basé sur un indice
  • Les "données" sont basées sur la CLÉ PRIMAIRE; chaque index secondaire est un arbre B + basé sur son index.
  • Le nœud feuille des "données" contient toutes les colonnes du tableau.
  • Le nœud feuille d'un index secondaire contient les colonnes de cet index secondaire, plus les colonnes de la CLÉ PRIMAIRE.

Si vous avez innodb_file_per_table = ON, Vous pouvez clairement voir le rétrécissement (le cas échéant) après OPTIMIZE TABLE en regardant la taille du fichier .ibd. Pour OFF, les informations sont enfouies dans ibdata1, Mais SHOW TABLE STATUS Peut être raisonnablement précis car tout l'espace "libre" appartient à chaque table. Eh bien, sauf pour les morceaux pré-alloués.

Vous remarquerez peut-être qu'une table de fichiers par table fraîchement optimisée contient exactement 4M, 5M, 6M ou 7M de Data_free. Encore une fois, il s'agit de la pré-allocation et de l'omission de vous donner les moindres détails.

Je travaille avec InnoDB depuis plus d'une décennie; J'ai travaillé avec des milliers de tables différentes, grandes et petites. Je dis qu'une seule table sur mille a vraiment besoin de OPTIMIZE TABLE. L'utiliser sur d'autres tables est un gaspillage.

105 colonnes, c'est beaucoup, mais peut-être pas trop.

Avez-vous 55 index sur la table n? C'est mauvais. Cela représente 55 mises à jour par INSERT. Discutons-en plus. Gardez à l'esprit que INDEX(a) est inutile si vous avez également INDEX(a,b). Et INDEX(flag) est inutile à cause de la faible cardinalité. (Mais INDEX(flag, foo) peut être utile.)

Q1: Il n'existe aucun bon moyen de vérifier toutes les formes de fragmentation dans les données ou les index secondaires.

Q2, Q3: OPTIMIZE TABLE Reconstruit la table par CREATEing une nouvelle table et INSERTing toutes les lignes, puis RENAMEing et DROPping. La réinsertion des données dans l'ordre PK garantit que le data est bien défragmenté. Les index sont une autre affaire.

Q4: Vous pourriezDROP et reCREATE chaque index pour le nettoyer. Mais c'est un processus extrêmement lent. 5.6 a quelques accélérations, mais je ne sais pas si elles aident à la défragmentation.

Il est également possible de ALTER TABLE ... DISABLE KEYS, Puis ENABLE les. Cela peut pour une reconstruction plus efficace de tous les index secondaires à la fois.

6
Rick James

Comment vérifier la fragmentation d'un index particulier dans MySQL, pas la table dans son ensemble

Passer.

OPTIMIZE TABLE corrige-t-il réellement la fragmentation interne/externe d'un index comme dans SQL Server?

Il reconstruit complètement la table et ses index.

Lorsque j'optimise une table dans MySQL, est-ce qu'il reconstruit tous les index de la table?

C'est la même question avec la même réponse.

Est-il réaliste de penser que réduire l'espace physique d'un index (sans reconstruire l'arbre lui-même) se traduit réellement par de meilleures performances?

Il n'est pas réaliste de penser que vous pourriez réduire l'espace sans reconstruire l'arbre. Ils vont ensemble.

1
user207421