Maintenance des index MySQL

12

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'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 de l'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 temps 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 «taux 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 réellement les enregistrements).

Cette table a été créée des années 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.

Les grandes questions sont donc:

  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?
Nicolas
la source
optimiser la table nettoie certainement l'index clusterisé sur innodb
1
c'est une excellente question, mais pas une question de programmation. Sera déplacé à l'endroit où il appartient:>

Réponses:

6

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 TABLEne 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'une "division de bloc". 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 c'est le cas innodb_file_per_table = ON, vous pouvez clairement voir le retrait (le cas échéant) après OPTIMIZE TABLE en regardant la .ibdtaille du fichier. Pour OFF, les informations sont enfouies ibdata1, mais SHOW TABLE STATUSpeuvent être raisonnablement précises 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 a 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 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 une table? C'est mauvais. C'est 55 mises à jour par INSERT. Discutons-en plus. Gardez à l'esprit que cela INDEX(a)ne sert à rien si vous l'avez également INDEX(a,b). Et INDEX(flag)est inutile en raison de la faible cardinalité. (Mais cela 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 TABLEreconstruit la table par CREATEingune nouvelle table et INSERTingtoutes les lignes, puis RENAMEinget DROPping. La réinsertion des données dans l'ordre PK garantit que les données sont bien défragmentées. Les index sont une autre affaire.

Q4: Vous pouvez DROP et reCREATEchaque 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 les faire ALTER TABLE ... DISABLE KEYSensuite ENABLE. Cela peut permettre une reconstruction plus efficace de tous les index secondaires à la fois.

Rick James
la source
Rick, je voulais dire '105' champs, pas des fichiers
Nicolas
1

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.

user207421
la source
Pour répondre # 1: Bien que ce ne soit pas très précis, SHOW TABLE STATUS LIKE 'mytable'cela donnerait un indice dans la data freecolonne. dev.mysql.com/doc/refman/5.6/en/show-table-status.html
Jehad Keriaki
Je sais, mais il manque encore l'espace d'un index particulier
Nicolas