Question

J'ai une grande base de données de données de commande normalisées qui devient très lente à interroger pour les rapports.La plupart des requêtes que j'utilise dans les rapports rejoignent cinq ou six tables et doivent examiner des dizaines ou des centaines de milliers de lignes.

Les requêtes sont nombreuses et la plupart ont été optimisées autant que possible pour réduire la charge du serveur et augmenter la vitesse.Je pense qu'il est temps de commencer à conserver une copie des données dans un format dénormalisé.

Des idées sur une approche?Dois-je commencer par quelques-unes de mes pires requêtes et partir de là ?

Était-ce utile?

La solution

J'en sais plus sur mssql que mysql, mais je ne pense pas que le nombre de jointures ou le nombre de lignes dont vous parlez devrait vous poser trop de problèmes avec les index corrects en place.Avez-vous analysé le plan de requête pour voir s'il vous en manque ?

http://dev.mysql.com/doc/refman/5.0/en/explain.html

Cela étant dit, une fois que vous êtes satisfait de vos index et que vous avez épuisé toutes les autres voies, la dénormalisation pourrait être la bonne réponse.Si vous n'avez qu'une ou deux requêtes qui posent problème, une approche manuelle est probablement appropriée, alors qu'une sorte d'outil d'entreposage de données pourrait être préférable pour créer une plate-forme permettant de développer des cubes de données.

Voici un site que j'ai trouvé et qui aborde le sujet :

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

Voici une technique simple que vous pouvez utiliser pour simplifier la dénormalisation des requêtes, si vous n'en effectuez que quelques-unes à la fois (et je ne remplace pas vos tables OLTP, j'en crée simplement une nouvelle à des fins de reporting).Supposons que vous ayez cette requête dans votre application :

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1

Vous pouvez créer une table dénormalisée et la remplir avec presque la même requête :

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided)

Notez que les traits de soulignement correspondent aux alias de table que vous utilisez

insert tbl_ab select a.id, a.name, b.address from tbla a
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything

Ensuite, pour corriger votre application afin qu'elle utilise la nouvelle table dénormalisée, remplacez les points par des traits de soulignement.

select a_name as name, b_address as address 
from tbl_ab where a_id = 1;

Pour les requêtes volumineuses, cela peut faire gagner beaucoup de temps et indiquer clairement d'où proviennent les données, et vous pouvez réutiliser les requêtes que vous avez déjà.

N'oubliez pas que je ne préconise cela qu'en dernier recours.Je parie qu'il existe quelques index qui pourraient vous aider.Et lorsque vous dénormalisez, n'oubliez pas de prendre en compte l'espace supplémentaire sur vos disques et de déterminer quand vous exécuterez la requête pour remplir les nouvelles tables.Cela devrait probablement avoir lieu la nuit ou lorsque l’activité est faible.Et les données de ce tableau, bien entendu, ne seront jamais exactement à jour.

[Encore une autre modification] N'oubliez pas que les nouvelles tables que vous créez doivent également être indexées !La bonne nouvelle est que vous pouvez indexer à votre guise sans vous soucier des conflits de verrouillage de mise à jour, car en dehors de votre insertion groupée, la table ne verra que les sélections.

Autres conseils

MySQL 5 prend en charge vues, ce qui peut être utile dans ce scénario.Il semble que vous ayez déjà fait beaucoup d'optimisation, mais sinon vous pouvez utiliser MySQL EXPLIQUER syntaxe pour voir quels index sont réellement utilisés et ce qui ralentit vos requêtes.

En ce qui concerne la normalisation des données (que vous utilisiez des vues ou que vous dupliquiez simplement des données de manière plus efficace), je pense que commencer par les requêtes les plus lentes et progresser est une bonne approche à adopter.

Je sais que c'est un peu tangentiel, mais avez-vous essayé de voir s'il existe d'autres index que vous pouvez ajouter ?

Je n'ai pas beaucoup d'expérience en base de données, mais je travaille beaucoup avec des bases de données récemment et j'ai découvert que de nombreuses requêtes peuvent être améliorées simplement en ajoutant des index.

Nous utilisons DB2 et il existe une commande appelée db2expln et db2advis, la première indiquera si les analyses de table ou les analyses d'index sont utilisées, et la seconde recommandera des index que vous pouvez ajouter pour améliorer les performances.Je suis sûr que MySQL a des outils similaires...

Quoi qu'il en soit, si c'est quelque chose que vous n'avez pas encore envisagé, cela m'a beaucoup aidé...mais si vous avez déjà emprunté cette voie, alors je suppose que ce n'est pas ce que vous recherchez.

Une autre possibilité est une "vue matérialisée" (ou comme on l'appelle dans DB2), qui vous permet de spécifier une table essentiellement constituée de parties provenant de plusieurs tables.Ainsi, plutôt que de normaliser les colonnes réelles, vous pouvez fournir cette vue pour accéder aux données...mais je ne sais pas si cela a de graves impacts sur les performances sur les insertions/mises à jour/suppressions (mais s'il est "matérialisé", cela devrait aider avec les sélections puisque les valeurs sont physiquement stockées séparément).

Conformément à certains des autres commentaires, j'examinerais certainement votre indexation.

Une chose que j'ai découverte plus tôt cette année sur nos bases de données MySQL était la puissance des index composites.Par exemple, si vous créez un rapport sur les numéros de commande sur des plages de dates, un index composite sur les colonnes de numéro de commande et de date de commande pourrait s'avérer utile.Je pense que MySQL ne peut utiliser qu'un seul index pour la requête, donc si vous aviez juste des index séparés sur le numéro de commande et la date de commande, il faudrait décider d'en utiliser un seul.L’utilisation de la commande EXPLAIN peut aider à déterminer cela.

Pour donner une indication des performances avec de bons index (y compris de nombreux index composites), je peux exécuter des requêtes joignant 3 tables de notre base de données et obtenir des résultats quasi instantanés dans la plupart des cas.Pour des rapports plus complexes, la plupart des requêtes s'exécutent en moins de 10 secondes.Ces 3 tableaux comportent respectivement 33 millions, 110 millions et 140 millions de lignes.Notez que nous les avions également déjà légèrement normalisés pour accélérer notre requête la plus courante sur la base de données.

Plus d'informations sur vos tables et les types de requêtes de reporting peuvent permettre d'autres suggestions.

Pour MySQL, j'aime cette présentation : Web du monde réel :Performances et évolutivité, édition MySQL.Celui-ci contient de nombreux conseils différents pour obtenir plus de vitesse avec MySQL.

Vous pouvez également envisager de sélectionner une table temporaire, puis d'effectuer des requêtes sur cette table temporaire.Cela éviterait d'avoir à rejoindre vos tables pour chaque requête que vous émettez (en supposant que vous puissiez utiliser la table temporaire pour de nombreuses requêtes, bien sûr).Cela vous donne essentiellement des données dénormalisées, mais si vous effectuez uniquement des appels sélectionnés, la cohérence des données ne pose aucun problème.

Suite à ma réponse précédente, une autre approche que nous avons adoptée dans certaines situations consiste à stocker les données clés des rapports dans des tableaux récapitulatifs distincts.Certaines requêtes de reporting seront tout simplement lentes même après la dénormalisation et les optimisations et nous avons constaté que la création d'un tableau et le stockage de totaux cumulés ou d'informations récapitulatives tout au long du mois au fur et à mesure de leur arrivée rendaient également les rapports de fin de mois beaucoup plus rapides.

Nous avons trouvé cette approche facile à mettre en œuvre car elle ne cassait rien de ce qui fonctionnait déjà : il s'agissait simplement d'insertions supplémentaires dans la base de données à certains moments.

J'ai joué avec les index composites et j'ai constaté de réels avantages... je vais peut-être configurer quelques tests pour voir si cela peut me sauver ici... au moins pour un peu plus longtemps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top