如何使用相同的WHERE子句有效地执行多个SQL查询

时间:2014-02-28 19:45:32

标签: sql ruby-on-rails-3 postgresql

我想做多个共享相同WHERE子句的SQL查询。我的查询都涉及计算各组中的条目数。目前我正在单独执行每个查询,这可能导致WHERE过滤器被多次应用。这似乎很浪费。有没有办法让我将我的查询组合在一起,这样WHERE子句只被调用一次?更一般地说,有没有办法让下面的查询更有效?

具体来说,假设我有一张公众人物表。

PublicFigures

last_name | occupation   | age   | state | has_dogs
---------------------------------------------------
Stewart   | comedian     |  51   | NY    | true
Colbert   | comedian     |  49   | NJ    | false
Obama     | president    |  52   | DC    | true
Romney    | consultant   |  66   | CA    | true
(etc..)

我想从表中提取两种类型的信息。首先,我想知道每个职业每个last_name出现的频率,其次,我想了解各州对狗的所有权数据。在这两种情况下,我只对55岁以下的公众人物感兴趣。因此,两个查询都使用相同的WHERE条款。

第一个查询,对于名称和职业,看起来像这样

SELECT last_name, occupation, COUNT(*) as count WHERE age < 55 FROM "PublicFigures" GROUP BY last_name, occupation

并给出了这个

last_name | occupation   | count
---------------------------------
Stewart   | comedian     |  1   
Stewart   | president    |  0
Colbert   | comedian     |  1 
Colbert   | president    |  0
Obama     | comedian     |  0
Obama     | president    |  1   

第二个问题是:

SELECT state, has_dogs, COUNT(*) as count WHERE age < 55 FROM "PublicFigures" GROUP BY state, has_dogs


state | has_dogs | count
---------------------------------------------------
NY    | true     | 1
NY    | false    | 0
NJ    | true     | 0
NJ    | false    | 0
DC    | true     | 1
DC    | false    | 1

有没有办法让这些结果比这两个查询分别更有效?这两个查询能以某种方式合并吗?

在现实生活中,当然,我的桌子更大,我有更多的查询,而且我的过滤条件更复杂。我认为从智能SQL中获得的节省是巨大的。如果可能的话,我特别感谢Rails3友好的ActiveRecord中的解决方案。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

例如,如果您可以通过创建索引来独立地使每个查询更快,那么这将是您最好的选择。如果没有,则创建一个临时表,然后重复查询而不是原始表:

create temporary table young_figures as 
    select * from public_figures where age < 55;

答案 1 :(得分:1)

这是索引创造奇迹的地方。另一种可以与索引创建相结合的方法是多次选择过滤器。希望这会给你带来一些东西,但正确的索引可能就是你所需要的。

CREATE INDEX pidx_public_figures_age ON public_figures (age)
WHERE age < 55;
--Try temp table with the index and also try just the new index and see if all your queries now run as fast as you would hope.
CREATE TEMPORARY TABLE temp_public_figures AS
 SELECT last_name, occupation ,age, state, has_dogs 
 FROM films WHERE age < 55;

现在针对实际表或临时表方法运行您的N个查询,并查看在您的用例下哪个表现更好

SELECT last_name, occupation, COUNT(*) as count 
FROM temp_public_figures
GROUP BY last_name, occupation;

SELECT state, has_dogs, COUNT(*) as count 
FROM temp_public_figures
GROUP BY state, has_dogs;