2009-02-10 7 views
4

Tenir compte une vue composée de plusieurs tables ... par exemple un , qui se compose des tables car réunis sur body, engine, wheels et stereo. Il pourrait ressembler à ceci:Optmizing MySQL GROUP BY ou sur de grandes vues DISTINCT

v_active_cars vue

SELECT * FROM car 
    INNER JOIN body ON car.body = body.body_id 
    INNER JOIN engine ON car.engine = engine.engine_id 
    INNER JOIN wheels ON car.wheels = wheels.wheels_id 
    INNER JOIN stereo ON car.stereo = stereo.stereo_id 
    WHERE car.active = 1 
    AND engine.active = 1 
    AND wheels.active = 1 
    AND stereo.active = 1 

Chaque composant de la voiture a un drapeau « actif ». Maintenant, je dois trouver tous les stéréos disponibles dans les voitures actives. Pour ce faire besoin d'utiliser l'ensemble de la vue, pas seulement la table stereo - juste parce qu'une chaîne stéréo est active ne signifie pas qu'il est disponible dans une voiture.

Je peux faire

SELECT DISTINCT stereo_id FROM v_active_cars 

Même si cela peut revenir un très petit nombre de lignes, il est Stil une requête très lente.

J'ai essayé, mais il est encore plus lent:

SELECT stereo_id FROM stereo WHERE EXISTS 
(SELECT 1 FROM v_active_cars WHERE stereo_id = stereo.stereo_id) 

Y at-il autre chose que je pouvais faire pour rendre ce plus rapide?

+0

Veuillez indiquer combien de lignes chaque table contient et combien de temps dure la requête. – Quassnoi

+0

yeh, quelques idées sur les nombres dans chaque table active et non active, et le nombre que vous revenez de votre vue. Si ses millions et prend quelques secondes, alors cela peut être tout ce que vous pouvez espérer, si ses centaines et prend quelques minutes, alors il peut y avoir quelque chose de mal –

Répondre

1
  1. assurez-vous qu'il ya des indices pour tous les JOIN
    • dans votre cas, chaque niveau est sélectionné à la fois par une clé, et un drapeau. l'ajout de l'indicateur dans le cadre de l'index pourrait permettre à la base de données d'utiliser uniquement l'index, au lieu de lire l'enregistrement complet
    • assurez-vous que vous avez assez de RAM pour contenir le jeu de résultats. Les tables InnoDB en particulier ont beaucoup de potentiomètres à régler. la plupart des défauts supposent très ancien matériel et trop peu de RAM.
+0

Votre point 3 s'applique à tous les paramètres de MySQL, pas seulement ceux d'InnoDB. – staticsan

+0

oui, juste que les valeurs par défaut InnoDB sont particulièrement minuscules par rapport aux normes d'aujourd'hui – Javier

1

Vous semblez tout faire correctement. L'étape suivante consisterait à vérifier la couverture de l'indice.

+0

Les index semblent bien, malheureusement:/ – Greg

+0

si vos index sont corrects, alors vous avez choisi la partie la plus courte obtenir le jeu de résultats. Malheureusement, vous devez maintenant régler le serveur/matériel db pour augmenter la performance. – Learning

0

Essayez ceci:

SELECT stereo_id 
FROM stereo s, (
    SELECT * 
    FROM v_active_cars 
    ORDER BY stereo_id 
) v 
WHERE s.active = 1 
    AND v.stereo = s.stereo_id 

ORDER BY ici devrait éviter de pousser prédicats dans la vue, et l'optimiseur doit sélectionner une jointure de hachage.

0

Vous pouvez essayer de créer une vue pour chaque partie en ne montrant que celles qui sont actives, puis vous joindre à celles-ci. par exemple.

VIEW activeCar 
SELECT * FROM car WHERE car.active = 1 

VIEW activeEngine 
SELECT * FROM engine WHERE engine.active = 1 

Ensuite, votre point de vue final peut être

SELECT * FROM activeCar 
INNER JOIN activeEngine ON activeCar.engine = activeEngine.engine_id 

faire toute évidence que vous avez un index sur la colonne active.

Une autre alternative est d'avoir un index sur l'identifiant et l'indicateur actif. Vous pouvez ensuite effectuer l'active = 1 lors de la jointure. De cette façon, un seul index est utilisé pour se joindre plutôt qu'un pour l'identifiant et un pour l'actif.

SELECT * FROM car 
INNER JOIN body ON car.body = body.body_id AND body.active = 1 
INNER JOIN engine ON car.engine = engine.engine_id AND engine.active = 1 
INNER JOIN wheels ON car.wheels = wheels.wheels_id AND wheels.active = 1 
INNER JOIN stereo ON car.stereo = stereo.stereo_id AND stereo.active = 1