2009-12-01 7 views
0

Je travaille sur un projet Rails et sur un problème de performances. Voici le schéma db simplifiéOptimisation de requête Mysql

 
table gaming_platforms (~5 rows) 
    id 

table games (~10k rows) 
    id 
    gaming_platform_id 
    winner    (black or white or n/a) 
    black_id   => online_players.id 
    white_id   => online_players.id 

table online_players (~1k rows) 
    id 
    gaming_platform_id 
    username 

maintenant donné un nom d'utilisateur, je veux afficher les joueurs dont le nom correspond à l'entrée, sans. des jeux qu'ils ont joués, gagnés ou perdus.

J'ai créé 3 vues pour éviter le problème 1 + n.

 
create or replace view online_player_games as 
     select online_players.id as online_player_id, count(*) as games 
     from games 
     left join online_players 
     on games.gaming_platform_id = online_players.gaming_platform_id and 
     (games.black_id = online_players.id or games.white_id = online_players.id) 
     group by online_players.id; 

create or replace view online_player_won_games as 
     select online_players.id as online_player_id, count(games.id) as games 
     from online_players 
     left join games on games.gaming_platform_id = online_players.gaming_platform_id and 
     ((games.winner = 1 and games.black_id = online_players.id) or (games.winner = 2 and games.white_id = online_players.id)) 
     group by online_players.id; 

create or replace view online_player_lost_games as 
     select online_players.id as online_player_id, count(games.id) as games 
     from online_players 
     left join games on games.gaming_platform_id = online_players.gaming_platform_id and 
     ((games.winner = 2 and games.black_id = online_players.id) or (games.winner = 1 and games.white_id = online_players.id)) 
     group by online_players.id; 

Sans utiliser d'index, il faut> 20 secondes pour interroger ces vues. La requête semble compliquée. Je ne suis pas sûr quels index je devrais créer. Toutes les opinions ou suggestions sont les bienvenues.

Répondre

1

Je pense que vous avez des problèmes généraux d'évolutivité avec votre conception. Au fur et à mesure que vous ajoutez des jeux et des utilisateurs, la façon dont vous comptez leurs gains/pertes deviendra un travail beaucoup plus important pour votre base de données du point de vue des E/S.

Je suggère de créer une table appelée player_record qui est simplement l'ID des joueurs, WINS, PERTE. Puis créez une procédure stockée qui est appelée quand un jeu se termine. (disons spGameFinished(game_id, winner,..);) Cette procédure stockée serait responsable de l'exécution des tâches nécessaires pour un jeu terminé, et l'une de ces tâches consiste à mettre à jour la table player_record en fonction de qui est déclaré le gagnant. Je suppose que lorsque le jeu commence, vous mettez le jeu avec les ID à 2 joueurs, mais si vous ne le faites pas, alors la procédure stockée devrait également prendre en charge à la fin du jeu. Une fois que cela est en place, les requêtes nécessaires à la collecte des informations de gain/perte sont triviales. Cela vous permet également de gérer les besoins de stockage des jeux séparément des enregistrements des joueurs. (Vous pouvez déposer des jeux qui sont vraiment vieux sans affecter un utilisateur enregistrement)

+0

Vous avez raison. Il vaut mieux utiliser une table pour stocker les statistiques des joueurs et les mettre à jour chaque fois que la table des jeux change. Je vais essayer l'approche de procédure stockée. –

0

J'ai créé une nouvelle online_player_stats de table avec des colonnes: online_player_id, games_as_black, games_won_as_black, games_lost_as_white, ...

J'ai aussi créé increment_online_player_stats et decrement_online_player_stats procs stockés qui sont appelés par des déclencheurs insert/update/delete.

Je prévois de créer une autre procédure stockée pour mettre à jour les statistiques de tous les joueurs en une seule fois pour amorcer et nettoyer si quelque chose ne va pas.

Cela semble-t-il une solution raisonnable?