2010-12-07 11 views
1

Ich habe die folgende Abfrage in 2 Datenbanken mit genau der gleichen Struktur getestet, in der ersten, mit 4M Einträge hat es mir das Ergebnis in 33 Sekunden zurückgegeben. Die zweite Tabelle hat 29 Millionen Zeilen und es sind 16 Stunden vergangen, seit ich die Abfrage ausgeführt habe, und ich habe noch keine Rückkehr erhalten.Abfrage Optimierung

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; 

Was kann ich diese Abfrage schneller machen ausführen?

Ist es wahrscheinlich, dass die Tabelle beschädigt ist oder so? Eine Tabelle ist nur 7 ~ 8 mal größer als die andere, aber es dauert 15000x mehr Zeit zu verarbeiten, ist das normal?

Alle anderen Kommentare sind willkommen!

Wenn mein Englisch nicht klar ist, lass es mich wissen, dass ich versuchen werde, mich auf eine andere Weise auszudrücken.

Vielen Dank für jede Hilfe,

ZUSÄTZLICHE INFORMATIONEN:

Aus den Variablen, die ich verwende, 3 von ihnen sind Indizes: id_hand, id_player, Position. Der Primärschlüssel ist (id_hand, id_player). Die Tabelle hat insgesamt 129 Spalten und 6 Indizes.

Ich lief auch EXPLAIN in beiden Tabellen und ich habe unterschiedliche Ergebnisse. Sowohl die Ergebnisse sind auf einer gdocs Tabelle: https://spreadsheets.google.com/ccc?key=tGxqxVNzHYznb1VVjtKyAuw&authkey=CJ-BiYkN&authkey=CJ-BiYkN#gid=0

+2

Ohne jede Vorstellung über Ihr Datenmodell und Indizes, dann ist es fast unmöglich, Ihnen zu helfen. Könnten Sie uns auch das Ergebnis von EXPLAIN zeigen? –

+0

Frank, wenn ich nach Hause komme, bekomme ich diese Informationen und poste sie. Vielen Dank. – joaoavf

+0

Machst du regelmäßig Vakuum auf diesem Tisch? –

Antwort

2

Möglicherweise verwenden Sie viel mehr Sortierspeicher für die größere Anzahl von Zeilen: Was ist Ihre work_mem Einstellung? Ähnlich verhält es sich mit dem Buffercache - da Sie die gleiche Tabelle mehrmals scannen, ist es wahrscheinlich entscheidend, Zeilen in den Cache einzupassen.

Außerdem sollten Sie diese Abfrage erneut untersuchen und versuchen, Wege zu finden, die Statistiktabelle nicht so oft auf sich selbst zu setzen. Es ist schwierig, ohne zumindest einige kleine Testdaten und erwartete Ausgabe zu beraten. Welche Version von PostgreSQL verwenden Sie? Mit 8.4 können Sie sowohl authtable als auch autxtable3 von mindestens einem CTE bekommen ...

+0

Araqnid, ich werde diese Einstellungen überprüfen, wenn ich nach Hause komme. Ich werde auch meine PostgreSQL-Version überprüfen, aber ich glaube, es ist 8.4, also werde ich versuchen, die Abfrage mit einem einzigen CTE zu erstellen. Was meinst du mit kleinen Testdaten und erwarteter Ausgabe? Ich kann versuchen, es zu bekommen. Vielen Dank. – joaoavf

3

Ich würde vorschlagen, dass die Indizierung entweder nonexistant oder falsch auf einem des Servers ist.

Es könnte auch eine Blockierung geben, die verhindert, dass die Abfrage beendet wird. Vor allem, wenn dort eine unverbindliche Transaktion stattfindet.

+0

Die beiden Tabellen wurden von derselben Anwendung erstellt, daher erwarte ich, dass sie genau dieselben Indizes haben. Andere Abfragen, die diese Spalten verwenden, funktionieren einwandfrei. Aber falls es ein Problem mit der Indexierung gibt, wie kann ich das überprüfen? – joaoavf

+0

Ich bin nicht sicher, wie Sie nach den Indizes in PostgreSQL suchen würden. – HLGEM

1

die Abfrage sieht gut aus. Um die Leistung zu verbessern, versuchen Sie die Indizierung wie @HLGEM zu tun. Versuchen Sie auch, jede einzelne Unterabfrage auszuführen, um festzustellen, welche eine niedrige Leistung hat.

1

Ich könnte leicht glauben, dass die Abfragen so viel länger dauern. Sie haben eine 29-M-Zeilentabelle, in der Sie mehrere Gruppen ausführen und in verschiedenen Spalten mehrmals mit sich selbst verknüpfen. Wenn die gesamte Tabelle nicht in den Speicher passt, kann eine große Anzahl von Paging-Vorgängen erforderlich sein, die bei 1/7 der Zeilen nicht benötigt werden.Arbeiten nach innen, Sie sind:

  1. Auswahl aus einer 29M Reihe Tabelle auf Position = 0 und cnt_players = 6
  2. Anbindung an Rücken eine 29M Reihe Tabelle auf der id_hand Spalte zweimal
  3. die Tabelle 29M Reihe Filtern zweimal für cnt_players = 6 und Positionen 0 und 8 und die durchschnittlichen flg_vpip durch Spieler Berechnung
  4. Anbindung an die gruppierten Ergebnisse auf id_hand für Millionen von Zeilen

Könnten Sie teilen die Tabelle in separat diejenigen? Was genau bedeuten Ihre Felder und wie würde eine Musterhand aussehen?

Sie würden Indizes mindestens auf id_player, id_hand, Position und cnt_players benötigen.

Es kann sinnvoll sein, alle Felder in den Index aufzunehmen. Ich bin mir nicht sicher über Postgresql, aber SQL Server kann das Laden der tatsächlichen Tabellendatenseiten überspringen, wenn alle Daten, die für eine Abfrage benötigt werden, im Index enthalten sind. Wenn Sie also einen Index für Position, cnt_players, id_player und flg_vpip hätten, wären Ihre innersten Auswahlen wahrscheinlich viel schneller.

Ein besserer Weg, denke ich wäre, diese inneren Selects im Voraus in eine oder zwei Tabellen zu berechnen, wenn Sie die Abfrage nicht oft ausführen.

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) 

So:

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

Der Deckungsindex wird in Postgres nicht helfen. Leider hat es keinen "index only scan" –