有没有办法在SQL select中优化子查询数组?

时间:2012-03-05 20:31:43

标签: sql postgresql query-optimization

我目前有两张桌子

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个答案。有没有办法优化上述内容?

3 个答案:

答案 0 :(得分:2)

您应该使用联接:

SELECT question.id, question.title, answer.votes
FROM question
JOIN answer ON answer.question_id == question.id
ORDER BY question.id

如果您希望输出列包含与问题相关联的所有“投票”的连锁列表,并且您使用的是Postgres,请查看以下问题:How to concatenate strings of a string field in a PostgreSQL 'group by' query?

答案 1 :(得分: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

答案 2 :(得分:0)

我建议您在answer表格上创建索引,并使用原始查询。

CREATE INDEX answer_question_id_idx ON answer(question_id);

如果没有此索引,则必须对整个表执行顺序扫描,以查找匹配question_id的行。每个问题都必须这样做。

或者,考虑使用联接,arc suggested。我不是这方面的专家,但我认为Postgres将使用散列连接而不是多个顺序扫描,从而使查询更快。如果要保留id / title / array格式,请使用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? | {}