lundi 21 septembre 2009

Sqlite : optimiser un COUNT() long

Sqlite à pour politique de ne pas stocker de meta data à propos du nombre de ligne des tables. C'est un choix justifiable car garder ces infos pour toutes les tables est couteux en ressources et ralenti donc forcément chaque INSERT/DELETE.
Parcourir une table lors du COUNT n'est donc pas très problématique sauf quand les tables atteignent un niveau important de données.
Mauvaise surprise pour moi lorsque ma page à mis plus de 1 min à s'afficher (base de 7Go et 500k enregistrements).
Pour résoudre le problème il faut émuler cette meta data avec 2 triggers et une tables supplémentaire.

On pourra par exemple créer une table "totaux" avec 3 champs "id","table" et "valeur". Il y'aura donc un enregistrement par table avec pour valeur le nombre de lignes de cette table.

Ne reste qu'à creer les deux triggers :
CREATE TRIGGER "count_delete_matable" AFTER DELETE ON maTable BEGIN UPDATE totaux SET valeur = valeur-1 WHERE table='maTable'; END;
CREATE TRIGGER "count_insert_matable" AFTER INSERT ON maTable BEGIN UPDATE totaux SET valeur = valeur+1 WHERE table='maTable'; END;

Ainsi après chaque enregistrement ajout ou supprimer le total sera automatiquement in/decrémenté.
Ne reste en suite qu'à remplacer les
SELECT COUNT(*) FROM maTable
par
SELECT valeur FROM totaux WHERE table='maTable'

Et là Ô magie , la page passe de plus d'1min à moins d'une demi seconde :)

Aucun commentaire: