2014-01-10 3 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), а столбцы идентификаторов, это должно хорошо работать.

Я также удалил все ненужные двойные кавычки, которые вызывали шумы кода.

+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 мс).

Как сказано в плане объяснения, на диске записано около 288 килобайт данных, так как данные не могут быть помещены в work_mem. Наложение локального work_mem на транзакцию заставит планировщика использовать быстрый вид в памяти, который должен быть намного быстрее, чем внешние слияния.

Смежные вопросы