2014-01-10 52 views
0

我有以下有點複雜SELECT聲明有多個連接,一組通過,並通過命令:優化複雜的Postgres SQL SELECT語句嗎?

SELECT 
    COUNT(*) AS count_all, 
    "response_variables"."id", 
    "response_variables"."var_name" AS "response_variables_id_response_variables_var_name" 
FROM "response_variables" 
    INNER JOIN "responses" ON "responses"."id" = "response_variables"."response_id" 
    INNER JOIN "questions" ON "questions"."id" = "responses"."question_id" 
WHERE "questions"."key" = 'rbmmpmvs' 
GROUP BY "response_variables"."id", "response_variables"."var_name" 
ORDER BY "response_variables"."var_name" ASC; 

下面是對運行EXPLAIN ANALYZE的輸出:

GroupAggregate (cost=720.80..723.20 rows=120 width=9) (actual time=277.127..285.953 rows=15265 loops=1) 
    -> Sort (cost=720.80..721.10 rows=120 width=9) (actual time=277.120..281.391 rows=15265 loops=1) 
     Sort Key: response_variables.var_name, response_variables.id 
     Sort Method: external merge Disk: 288kB 
     -> Nested Loop (cost=0.00..716.66 rows=120 width=9) (actual time=0.064..21.795 rows=15265 loops=1) 
       -> Nested Loop (cost=0.00..657.78 rows=128 width=4) (actual time=0.050..7.919 rows=3042 loops=1) 
        -> Index Scan using index_questions_on_key on questions (cost=0.00..8.27 rows=1 width=4) (actual time=0.032..0.033 rows=1 loops=1) 
          Index Cond: ((key)::text = 'rbmmpmvs'::text) 
        -> Index Scan using index_responses_on_question_id on responses (cost=0.00..646.69 rows=282 width=8) (actual time=0.016..7.326 rows=3042 loops=1) 
          Index Cond: (question_id = questions.id) 
       -> Index Scan using index_response_variables_on_response_id on response_variables (cost=0.00..0.42 rows=4 width=13) (actual time=0.002..0.003 rows=5 loops=3042) 
        Index Cond: (response_id = responses.id) 
Total runtime: 288.766 ms 
(13 rows) 

我有一個不同點數的索引數量,但不知道從哪裏開始優化通話(或者如果可能的話)。

+2

您目前的work_mem設置是什麼?看起來你可以使用額外的東西:SET work_mem TO'100MB'; –

+1

+1 @FrankHeikens甚至更多,以獲得HashAggregate計劃。 –

回答

0

where子句中的條件適用於最內部連接的表。這很糟糕,因爲必須在之前完成所有加入,發現問題行的匹配或不匹配。

相反,列出問題表第一,反轉表順序:

SELECT 
    COUNT(*) AS count_all, 
    response_variables.id, 
    response_variables.var_name AS response_variables_id_response_variables_var_name 
FROM questions 
JOIN responses ON questions.id = responses.question_id 
JOIN response_variables ON responses.id = response_variables.response_id 
WHERE questions.key = 'rbmmpmvs' 
GROUP BY response_variables.id, response_variables.var_name 
ORDER BY response_variables.var_name 

只要有上question(key)的指標,ID列,這應該表現良好。

我還刪除了導致代碼噪聲的所有不必要的雙引號。

+0

對錶格進行重新排序在Postgres中將沒有什麼區別,因爲規劃師會盡其所能地嘗試每個順序的連接,除非有一個(可配置的)大量的連接。 –

0

試試這個:

SELECT 
    COUNT(*) AS count_all, 
    response_variables.id, 
    response_variables.var_name AS response_variables_id_response_variables_var_name 
FROM questions 
WHERE 1=1 
AND EXISTS (Select 1 from responses where responses.id = questions.id) 
AND EXISTS (Select 1 from response_variables where response_variables.id = questions.id) 
AND questions.key = 'rbmmpmvs' 
GROUP BY response_variables.id, response_variables.var_name 
ORDER BY response_variables.var_name 

而且,您的查詢是做一個基於磁盤的外部合併,這可能會非常緩慢,而且時間大約90%在排序(259.596毫秒)度過的。

正如在解釋計劃中所說的,大約288kb的數據被寫入磁盤,因爲它的數據無法放入work_mem中。爲事務爭取本地work_mem將強制規劃者使用內存中的快速排序,這應該比外部合併排序快得多。