2012-03-05 49 views
1

我現在有兩個表有沒有辦法在SQL select中優化子查詢的數組?

question 
-------- 
id 
title, character varying 

answer 
-------- 
id 
question_id 
votes, integer 

我用下面的查詢返回了我的問題的列表及其相應票數的數組:

SELECT question.id, 
    question.title, 
    ARRAY(SELECT votes 
      FROM answer 
      WHERE answer.question_id = question.id) 
FROM question 
ORDER BY question.id 

輸出看起來像:

id | title | ?column?      
----+----------+----------------------------------------------------- 
100 | How to | {5,2,7} 
101 | Where is | {0} 
102 | What is | {1} 

上述查詢可能需要近50秒才能運行數十萬個問題,其中每個問題至少可以有5個答案。有沒有一種方法來優化以上?

+1

添加postgresql標籤b/c,看起來像特定於postgres的語法。如果這不是一個正確的評估,請隨時刪除標籤。 – bernie 2012-03-05 20:34:46

+0

表「answer」的'votes'列的類型是什麼?它是一個數組還是一個整數值?我假設它是一個單一的'int'值。如果它是一個數組,則您的查詢不起作用。 – 2012-03-05 20:49:46

+0

這是一個整數 – 2012-03-05 20:53:21

回答

0

我建議您在answer表上創建索引,並使用原始查詢。

CREATE INDEX answer_question_id_idx ON answer(question_id); 

沒有這個指標,它會做整個表的順序掃描,以找到匹配的question_id行。它必須爲每個問題都做到這一點。

或者,考慮使用連接,因爲arc suggested。我不是這方面的專家,但我認爲Postgres將使用散列連接而不是多個順序掃描,使查詢更快。如果您想保留ID /標題/陣列格式,請使用array_agg

SELECT question.id, question.title, array_agg(answer.votes) 
    FROM question 
    LEFT JOIN answer ON answer.question_id = question.id 
GROUP BY question.id, question.title 
ORDER BY question.id; 

然而,有一點需要注意。如果問題沒有答案,你會得到一個奇怪的前瞻性結果:

id |  title  | array_agg 
----+-------------------+----------- 
    1 | How do I do this? | {3,5} 
    2 | How do I do that? | {NULL} 
(2 rows) 

這是因爲LEFT JOIN,它創建可用時沒有從連接錶行的NULL價值。隨着INNER JOIN,第二行將不會出現。

這就是爲什麼我建議使用您的原始查詢。它產生了預期的結果:

id |  title  | ?column? 
----+-------------------+---------- 
    1 | How do I do this? | {3,5} 
    2 | How do I do that? | {} 
+0

我已經有了這個索引,它仍然需要一段時間。使用'EXPLAIN'後,我沒有看到使用連接方法的很多改進。 – 2012-03-05 21:15:17

0

如果您想查詢生產每題一行,聚集到一個數組票,你可以使用一個連接,與array_agg

SELECT question.id, 
    question.title, 
    array_agg(answer.votes) as answer_votes 
FROM question 
JOIN answer ON answer.question_id = question.id 
GROUP BY question.id, question.title 
ORDER BY question.id 
相關問題