2010-12-07 137 views
1

我測試了2個數據庫中具有完全相同結構的以下查詢,第一個具有4M條目,它在33秒內返回了結果。第二個表有29M行,自從我執行查詢後已經過了16個小時,我還沒有收到回報。查詢優化

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; 

我能做些什麼,使這個查詢執行得更快?

表有可能是損壞或類似的東西?一張桌子只比另一張桌子大7〜8倍,但它需要15000倍的時間來處理,這是正常的嗎?

歡迎任何其他意見!

如果我的英語不清楚,只要告訴我,我會試着用不同的方式表達自己。

非常感謝您的幫助,

附加信息:

從我使用,其中3人爲索引變量:id_hand,id_player,位置。主鍵是(id_hand,id_player)。該表共有129列和6個索引。

我也在兩個表中運行了EXPLAIN,得到了不同的結果。無論是 結果是在gdocs電子表格: https://spreadsheets.google.com/ccc?key=tGxqxVNzHYznb1VVjtKyAuw&authkey=CJ-BiYkN&authkey=CJ-BiYkN#gid=0

+2

沒有關於你的數據模型和索引的任何想法,這幾乎是不可能幫助你。你能否向我們展示EXPLAIN的結果? – 2010-12-07 20:20:28

+0

弗蘭克,當我到家時,我會得到這些信息併發布。謝謝。 – joaoavf 2010-12-07 21:48:26

+0

你在那張桌子上經常抽真空嗎? – 2010-12-08 08:14:03

回答

2

可能您使用更多排序內存來存儲更多行數:您的work_mem設置是什麼?與buffercache類似,由於您多次掃描同一個表,因此將行整合到緩存中可能至關重要。

此外,您應該重新檢查該查詢,並嘗試找到不必將統計表重新加入自己多次的方法。如果沒有至少一些小的測試數據和預期的輸出,很難提供建議。你使用的是哪個版本的PostgreSQL?在8.4的情況下,您可能至少可以從單個CTE獲得輔助工作站和輔助工作站3 ...

3

我會建議索引或者是不存在的或不正確的服務器之一。

也可能阻止查詢完成。特別是如果有一個沒有提交的交易坐在那裏。

1

查詢看起來不錯。以提高性能嘗試像@HLGEM所說的做索引。 也嘗試執行每個單獨的子查詢,以查看哪一個具有較低的性能。

1

我很容易相信這些查詢需要花費更長的時間。你有一個29M的行表,你正在做多個組,並在不同的列上多次鏈接自己。如果整個表格不適合內存,則可能會涉及大量的分頁,而這些分頁在1/7行中不需要。工作向內,你是:

  1. 從位置29M排表中選擇= 0和cnt_players = 6
  2. 鏈接回一個29M行的表上id_hand柱兩次
  3. 過濾29M行表兩次對於cnt_players = 6位0和8,並通過播放器
  4. 鏈接到分組結果對id_hand數百萬行的計算平均flg_vpip

你能拆表爲單獨的?你的領域究竟是什麼意思,樣本手是什麼樣的?

您至少需要id_player,id_hand,position和cnt_players上的索引。

將所有字段包含在索引中可能會很好。我不確定postgresql,但如果查詢所需的所有數據都在索引中,SQL Server可以跳過加載實際的表數據頁面。所以如果你有一個位置索引,cnt_players,id_player和flg_vpip,那麼你最內層的選擇可能會快得多。

如果你不打算頻繁地運行查詢,我認爲一種更好的方法是將這些內部選擇提前計算到一個或兩個表中。

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) 

像這樣:

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