2010-10-11 13 views
0

Voilà ma requête en cours:sérieuses SQL Optimisation des requêtes nécessaires (MySQL)

SELECT IFNULL(sum(open_for), 0) total, count(IF(open_for > 0, 1, null)) wins, count(IF(open_for < 0, 1, null)) losses FROM `sport_points` WHERE (sportable_id = 1 and sportable_type = 'Team' and game_time > '2010-07-13 11:39:58 UTC' 

Il renvoie essentiellement ces données agrégées:

EQUIPE A

  • open_for
  • total: 2000
  • gagne: 20
  • pertes: 12

Maintenant, imaginez qu'il y ait environ 6 autres colonnes dans la table dont j'ai besoin exécuter des requêtes séparées pour obtenir toutes les données agrégées spécifiques aux colonnes pour une équipe. Par exemple:

SELECT IFNULL(sum(FINAL_FOR), 0) total, count(IF(open_for > 0, 1, null)) wins, count(IF(open_for < 0, 1, null)) losses FROM `sport_points` WHERE (sportable_id = 1 and sportable_type = 'Team' and game_time > '2010-07-13 11:39:58 UTC' 

EQUIPE A

  • final_for
  • au total: 4000
  • victoires: 40
  • pertes: 18

Le problème avec cette approche est que Je dois exécuter environ 6 requêtes distinctes pour toutes les colonnes bien au-dessus 200 équipes. C'est un sérieux problème de charge.

Idéalement, la requête renverrait toutes les données agrégées spécifiques aux colonnes pour une équipe - dans une requête. Il ressemblerait à ceci dans le résultat:

EQUIPE A

  • open_for_total
  • open_for_wins
  • open_for_losses
  • final_for_total
  • final_for_wins
  • final_for_losses

... etc ...

+0

6 requêtes séparées Je peux comprendre, mais il semble que ces requêtes peuvent être regroupées par ID d'équipe afin que vous obteniez les résultats des 200 équipes dans les 6 requêtes différentes. 6 requêtes ne doivent pas présenter de problème de chargement avec 200 équipes. Avez-vous indexé vos tables correctement? – methodin

+0

cette approche pourrait fonctionner ... cependant, je ne veux pas toujours les 200 équipes à la fois ... peu importe, ce peut être une option ... à quoi ressemblerait le sql? – keruilin

Répondre

0

Juste au profit de ceux qui veulent aider:

Requête 1:

SELECT 
    IFNULL(sum(open_for), 0) total 
    ,COUNT(IF(open_for > 0, 1, null)) wins 
    ,COUNT(IF(open_for < 0, 1, null)) losses 
FROM 
    `sport_points` 
WHERE 
    sportable_id = 1 
    AND sportable_type = 'Team' 
    AND game_time > '2010-07-13 11:39:58 UTC' 

Requête 2:

SELECT 
    IFNULL(SUM(FINAL_FOR), 0) total 
    ,COUNT(IF(open_for > 0, 1, null)) wins 
    ,COUNT(IF(open_for < 0, 1, null)) losses 
FROM 
    `sport_points` 
WHERE 
    sportable_id = 1 
    AND sportable_type = 'Team' 
    AND game_time > '2010-07-13 11:39:58 UTC' 

souhaitee colonnes de sortie: teamname, typeofquery, valeur

Où Type de requête est l'un de:

  • open_for_total
  • open_for_wins
  • open_for_losses
  • final_for_total
  • final_for_wins
  • final_for_losses

provenant des deux colonnes open_for et final_for conjointement avec le wins et losses colum ns.

Initialement en pensant au problème, je suppose qu'une table intermédiaire pourrait aider à traiter avec une clause GROUP BY.

par exemple.

INSERT INTO 
    temptable 
SELECT 
    teamname 
    ,'open_for' type 
    ,IFNULL(SUM(open_for), 0) total 
    ,COUNT(IF(open_for > 0, 1, null)) wins 
    ,COUNT(IF(open_for < 0, 1, null)) losses 
FROM 
    `sport_points` 
WHERE 
    sportable_id = 1 
    AND sportable_type = 'Team' 
    AND game_time > '...' 
GROUP BY 
    teamname 

puis d'exécuter la même requête, mais en sommant final_for. Maintenant, votre table temporaire contient des lignes comme:

teamname, type, total, wins, losses 
TEAM A, open_for, 100, 37, 63 
TEAM A, final_for, 30, 10, 20 
TEAM B, open_for, 12, 8, 4 
TEAM B, final_for, 50, 49, 1 

Votre requête finale pourrait simplement concaténer les colonnes comme vous le souhaitez.

0

Je le ferais en une seule requête qui renvoie des colonnes séparées pour chacune des statistiques. Je restructurerais alors les résultats dans mon code d'application si nécessaire. La requête ressemble à quelque chose comme:

select teamname, 
sum(open_for) as open_total, 
count(if(open_for > 0, 1, null)) as open_wins, 
count(if(open_for < 0, 1, null)) as open_losses, 
sum(final_for) as final_total, 
count(if(final_for > 0, 1, null)) as final_wins, 
count(if(final_for < 0, 1, null)) as final_losses, 
from sport_points 
where sportable_id = 1 
and sportable_type = 'Team' 
and game_time > '...' 
group by teamname 

, je suggère, est une approche relationnelle plus orthodoxe, et donc celui qui est facilement exprimée en SQL. Si ce n'est pas tout à fait ce dont vous avez besoin dans votre application, alors l'endroit où effectuer l'ajustement est en code, ce qui est beaucoup plus flexible que SQL.

+0

Vous pouvez facilement restreindre cela à un sous-ensemble d'équipes (ou même à des lignes, quelles qu'elles soient) si vous le souhaitez - vous ajoutez simplement des conditions à la clause where comme d'habitude. –