2010-12-07 34 views
1

J'ai testé la requête suivante dans 2 bases de données avec exactement la même structure, dans la première, avec des entrées 4M, elle m'a renvoyé le résultat en 33 secondes. La deuxième table a 29M lignes et cela fait 16 heures que j'ai exécuté la requête et je n'ai pas encore de retour.Optimisation de requête

SELECT sbvpip*4 as smallbvpip,btnvpip*4 as buttonvpip, sum(amt_won)*400/count(*) AS winrate, count(*) as count 

FROM holdem_hand_player_statistics 

    JOIN (

    SELECT id_player AS pid2, id_hand AS hid, sbvpip 
    FROM holdem_hand_player_statistics 

     JOIN (
     SELECT id_player AS pid, ROUND(avg(flg_vpip::int)*25) AS sbvpip 
     FROM holdem_hand_player_statistics 
     WHERE position = 8 AND cnt_players = 6 
     GROUP BY id_player 
     ) AS auxtable 
     ON pid = id_player 

    WHERE position = 8 AND cnt_players = 6 
    ) AS auxtable2 
    ON hid = id_hand 


    JOIN (

    SELECT id_player AS pid4, id_hand AS hid2, btnvpip 
    FROM holdem_hand_player_statistics 

     JOIN (
     SELECT id_player AS pid3, ROUND(avg(flg_vpip::int)*25) AS btnvpip 
     FROM holdem_hand_player_statistics 
     WHERE position = 0 AND cnt_players = 6 
     GROUP BY id_player 
     ) AS auxtable3 
     ON pid3 = id_player 

    WHERE position = 0 AND cnt_players = 6 
    ) AS auxtable4 
    ON hid2 = id_hand 


WHERE POSITION = 0 and cnt_players = 6 



GROUP BY sbvpip,btnvpip 
ORDER BY 1,2; 

Que puis-je faire pour exécuter cette requête plus rapide?

Est-il probable que la table soit corrompue ou quelque chose comme ça? Une table est seulement 7 ~ 8 fois plus grande que l'autre, mais cela prend 15000x plus de temps à traiter, est-ce normal?

Tous les autres commentaires sont les bienvenus!

Si mon anglais n'est pas clair, faites-moi savoir que je vais essayer de m'exprimer d'une manière différente.

Merci beaucoup pour toute aide,

INFO ADDITIONNELLE:

à partir des variables que j'utilise, trois d'entre eux sont des indices: id_hand, id_player position. La clé primaire est (id_hand, id_player). La table a 129 colonnes et 6 index au total.

J'ai aussi couru EXPLAIN dans les deux tableaux et j'ai obtenu des résultats différents. Les deux résultats sont sur une feuille de GDocs: https://spreadsheets.google.com/ccc?key=tGxqxVNzHYznb1VVjtKyAuw&authkey=CJ-BiYkN&authkey=CJ-BiYkN#gid=0

+2

Sans aucune idée de votre modèle de données et les index, il est presque impossible de vous aider. Pourriez-vous également nous montrer le résultat d'EXPLAIN? –

+0

Frank, quand j'arriverai à la maison, je recevrai cette information et je la posterai. Merci. – joaoavf

+0

Faites-vous de l'aspirateur régulier sur cette table? –

Répondre

2

Peut-être que vous utilisez beaucoup plus de mémoire de tri pour le plus grand nombre de lignes: quel est votre réglage work_mem? De même avec le buffercache, puisque vous scannez la même table plusieurs fois, l'insertion de lignes dans le cache est susceptible d'être cruciale.

En outre, vous devriez réexaminer cette requête et essayer de trouver des moyens de ne plus avoir à se joindre à la table de statistiques tant de fois. Il est difficile de conseiller sans au moins quelques petites données de test et la sortie attendue. Quelle version de PostgreSQL utilisez-vous? Avec 8.4, vous pourriez obtenir à la fois l'auxtable et l'auxtable3 à partir d'un seul CTE au moins ...

+0

Araqnid, je vais vérifier ces paramètres quand je rentre à la maison. Je vais aussi vérifier ma version de PostgreSQL, mais je crois que c'est 8.4, donc je vais essayer de construire la requête en utilisant un seul CTE. Qu'entendez-vous par petites données de test et résultats attendus? Je peux essayer de l'obtenir. Merci. – joaoavf

3

Je suggère que l'indexation est soit inexistante ou incorrecte sur l'un des serveurs.

Il peut également y avoir un blocage empêchant la fin de la requête. Espciellement s'il y a une transaction non engagée assise là-bas.

+0

Les deux tables ont été créées par la même application, donc je m'attends à ce qu'elles aient exactement les mêmes index. D'autres requêtes utilisant ces colonnes fonctionnent bien. Mais au cas où il y aurait un problème avec l'indexation, comment puis-je le vérifier? – joaoavf

+0

Je ne sais pas comment vous rechercheriez les index dans PostgreSQL. – HLGEM

1

La requête semble correcte. pour améliorer les performances, essayez de faire l'indexation comme @HLGEM dit. Essayez également d'exécuter chaque sous-requête pour voir laquelle a de faibles performances.

1

Je pourrais facilement croire que les requêtes prennent beaucoup plus de temps. Vous disposez d'une table de lignes de 29 Mo sur laquelle vous effectuez plusieurs groupes et vous liez plusieurs fois sur plusieurs colonnes différentes. Si la totalité de la table ne rentre pas dans la mémoire, il peut y avoir beaucoup de pagination qui n'est pas nécessaire avec 1/7ème des rangées.vers l'intérieur de travail, vous êtes:

  1. Sélection d'une table de ligne de 29M sur la position = 0 et cnt_players = 6
  2. créant un lien à une table de ligne de 29M sur la colonne id_hand deux fois
  3. Filtrage de la table rangée de 29M deux fois pour cnt_players = 6 et positions 0 et 8 et le calcul de la moyenne flg_vpip par le joueur
  4. Liens vers les résultats groupés sur id_hand pour des millions de lignes

Pourriez-vous diviser la table en les séparés? Que signifient exactement vos champs et à quoi ressemblerait un échantillon?

Vous auriez besoin d'index sur id_player, id_hand, position et cnt_players au moins.

Il peut être utile d'inclure tous les champs dans l'index. Je ne suis pas sûr de postgresql, mais SQL Server peut ignorer le chargement des pages de données de la table si toutes les données dont il a besoin pour une requête se trouvent dans l'index. Donc, si vous aviez un index sur la position, cnt_players, id_player et flg_vpip, vos sélections les plus internes seraient probablement beaucoup plus rapides.

Une meilleure façon, je pense, serait de calculer ces sélections internes à l'avance dans une table ou deux si vous n'allez pas exécuter la requête souvent.

select id_player, position, cnt_players, 
    ROUND(avg(flg_vpip::int)*25) AS avg_vpip 
into auxtable 
from holdem oldem 
group by id_player, position, cnt_players 

alter table auxtable add constraint PK_auxtable 
    primary key clustered (id_player, position, cnt_players) 

Comme ceci:

SELECT sbvpip*4 as smallbvpip,btnvpip*4 as buttonvpip, sum(amt_won)*400/count(*) AS winrate, count(*) as count 
FROM holdem 
    JOIN (
     SELECT id_player AS pid2, id_hand AS hid, sbvpip 
     FROM holdem 
      JOIN auxtable ON auxtable.id_payer = holdem.id_player 
       and auxtable.position = holdem.position 
       and auxtable.cnt_players = holdem.cnt_players 
     WHERE holdem.position = 8 AND holdem.cnt_players = 6 
    ) AS auxtable2 ON hid = id_hand 
+0

L'index de couverture n'aidera pas dans Postgres. Malheureusement, il n'a pas de "scan d'index seulement" –