Si vous avez des tables très grosses qui ne servent qu'à accumuler des données d'état, par exemple un journal ou des tables d'extension de relation 1-1 avec un une fk et de lourdes données texte l'engine ARCHIVE peut-être un bon choix.
En effet, les tables avec engine archive sont très très économes.
Ce n'est pas la première fois que je parle de cela : http://moosh.et.son.brol.be/blog/index.php/2009/02/24/919-mysql-archive-et-partition
J'ai recommence mon test. Je pars sur une table de 2 champs et je la rempli avec 7M d'enregistrements
id int(10) unsigned NOT NULL DEFAULT '0',
BlahBlahBienLourd text NOT NULL
En chiffres...
En sql le fichier de donnée occupe 1.5Go.
Je décline la table en plusieurs versions
CREATE TABLE test_myisam () ENGINE=myisam
CREATE TABLE test_myisam_with_index () ENGINE=myisam
CREATE TABLE test_archive () ENGINE=archive
CREATE TABLE test_archive_with_partition () ENGINE=archive PARTITION BY KEY (id) PARTITIONS 10
Les 3 fichiers (frm, MYD, MYI) de la table test_myisam occupent 1.45Go
Les 3 fichiers (frm, MYD, MYI) de la table test_myisam_with_index occupent 1.5Go
Les 2 fichiers (frm, ARZ) de la table test_archive en 10 partitions occupent 272Mo !!
Les 12 fichiers (frm, par, 10x ARZ) de la table test_archive_with_partition en 10 partitions occupent aussi 272Mo !!
Cela me donne une économie de presque 6x.
C'est déjà très intéressant. (Ca reste très variable car c'est compressé)
Mais il y a quelque chose de vraiment très gênant. Avec Archive, pas d'index.
Hors je teste avec 7M enregistrements mais ma table réelle compte près de 80M enregistrements. Si je cherche une entrée, même par id. Ca se fera en scan et ca fait mal.
Petit test
Je cherche un row par son id.
- Une sur la table test_myisam : 36s
- Une sur la table test_myisam_with_index : 0.13s. Il n'y a pas photo
- Une sur la table test_archive : 15s
Je n'ai pas compris pourquoi ca va plus vite que sur test_myisam, mais ca reste inacceptable.
Comment garder les avantages d'archive mais pouvoir y chercher une donnée de manière raisonnable ?
La solution : combiner archive avec un partition by key() partitions xxx.
Je refais ma cherche sur un row par son id.
- Sur ma table archive mais en 10 partitions : 1.6s !!!
Sur le coup je rajoute une copie de ma table mais avec 100 partitions. (129 secondes pour la remplir sur mon vieux brol)
Premier constat, ça prend beaucoup plus de place : 367Mo.
mais j’obtiens mon résultat en 0.33s
Reste à trouver le juste milieu mais la démonstration est faite.
Si je reprends ma table de 80M de row avec un partitions 100, je me retrouve alors avec 100 fichiers de 800k rows.
Ce qui est très raisonnable pour un scan occasionnel.
Un autre avantage de la combinaison archive + partition.
Dans le cas précédent j'ai choisi un partition by key, donc avec une répartition des row dans l'ensemble des partitions.
Si je passe à un partitionnement en range, avec une remplissage séquentiel, on va profiter d'un autre avantage (au détriment du précédent)
Imaginez que vous avez 10K insert par jour que vous voulez garder 6mois d'archives
La table archive pose problème puisqu'on ne peut pas faire de delete
Normalement pour supprimer, il faut créer une nouvelle table et dumper le contenu que l'on veut conserver.
C'est fastidieux et en plus cela veut dire que pendant une durée, votre table n'est pas utilisable.
Solution toute trouvée avec les partitions (qui en fait est tout à fait valable sur les autres moteurs que archive)
Je choisi donc un partition by range, soit sur l'id, soit sur une date.
Si vous avez un journal, vous avez sûrement un champ date.
On fait des partitions basées sur le mois, chaque mois une nouvelle partition.
Premièrement un script va périodiquement vérifier qu'il y a au moins 2 partitions vides.
Si ce n'est pas le cas, une nouvelle partition est ajoutée.
Ensuite on observe la plus vieille partition, si elle ne contient que des données périmées, on supprime la partition.
Pour supprimer une partition :
ALTER TABLE <tblname> DROP PARTITION <partition_name>
De cette manière vous avez un stockage très léger, une suppression instantanée d'un grand nombre de rows et ce sans charge mysql, ...
En outre vous gardez l'avantage des recherches "rapides" pour autant qu'elles se fasse bien sur le champs choisi pour le partitionnement.
Cette solution est à expérimenter car il faut choisir les bonnes bornes, gérer le problème des noms des partitions...
Voici un article qui propose un système de rotations
Rappel des limitations du moteur ARCHIVE
- ne supporte que les commandes INSERT et SELECT : aucun effacement, remplacement ou modification.
- Une commande SELECT effectue un scan de table complet.
- Vous pouvez utiliser la commande OPTIMIZE TABLE pour analyser la table, et compresser encore plus.
- Le moteur de table ARCHIVE utilise un verrouillage de ligne.
Rappel des limitations des partitions
- Lors de la création de tables avec un nombre très important de partitions, l'erreur 24 peut tomber. Dans ce cas de figure augmenter le paramètre open_files_limit du serveur.
- Les tables partitionnées ne supportent pas les clés étrangères (moteur InnoDB).
- Les tables partitionnées ne supportent pas les indexes FULLTEXT.
- Les tables partitionnées ne supportent pas les colonnes GEOMETRY.
- Les moteurs de stockage MERGE et CSV ne supportent pas le partitionnement de tables.
- Le partitionnement par KEY (ou LINEAR KEY) est le seul type de partitionnement supporté par le moteur de stockage NDB.
- Lors d'un upgrade, les tables partitionnées de type KEY et utilisant un moteur de stockage autre que NDBCLUSTER doivent être déchargées et rechargées.
- Toutes les partitions et sous partitions doivent utiliser le même moteur de stockage.
- Une clé de partitionnement doit être un entier ou une expression qui retourne un entier. La colonne ou l'expression peut avoir des valeurs NULL. La seule exception est le partitionnement par KEY ou LINEAR KEY pour lequel les autres types de colonnes qu'un entier sont autorisés. Lestypes de colonnes BLOB et TEXT ne sont pas autorisés cependant.
- Une clé de partitionnement ne peut être une sous requête, même si cette dernière retourne une valeur entière.
- Toutes les colonnes utilisées dans l'expression de partitionnement doivent faire partie d'une clé unique ou de la clé primaire que la table peut comprendre.
Autres liens
- http://www.sitepoint.com/mysql-archive-engine-data-retention/