2016-07-27 5 views
1

У меня есть запрос, который довольно сложный, он имеет несколько внутренних объединений, а также дополнительный выбор. Он выполняет ужасающе:Улучшение производительности запросов JOIN и sub SELECT

EXPLAIN ANALYZE SELECT 
    SUM(weekly_baskets.servings/2) AS sum_weekly_baskets_servings_2, 
    meal_selections.meal_id AS meal_selections_meal_id 
FROM 
    "meal_selections" 
INNER JOIN 
    "weekly_baskets" "weekly_baskets_meal_selections" 
     ON "weekly_baskets_meal_selections"."id" = "meal_selections"."weekly_basket_id" 
INNER JOIN 
    "weekly_baskets" 
     ON "meal_selections"."weekly_basket_id" = "weekly_baskets"."id" 
WHERE 
    "weekly_baskets"."menu_id" = 344 
    AND (
     NOT (EXISTS (SELECT 
     1 
     FROM 
     "cancellations" 
     WHERE 
     ("cancellations"."cancellable_id" = "weekly_baskets"."id") 
     AND ("cancellations"."cancellable_type" = 'WeeklyBasket') 
     AND "cancellations"."active" = 't')) 
    ) 
GROUP BY 
    meal_selections.meal_id 

Вот план запроса:

HashAggregate (cost=122273.42..122275.79 rows=787 width=8) (actual time=32313.598..32313.602 rows=13 loops=1) 
    Group Key: meal_selections.meal_id 
    -> Nested Loop (cost=26501.36..122208.17 rows=43504 width=8) (actual time=97.199..32292.526 rows=48594 loops=1) 
     -> Nested Loop (cost=26501.28..119314.73 rows=19567 width=12) (actual time=97.175..20446.310 rows=16067 loops=1) 
       -> Nested Loop Anti Join (cost=26501.19..87846.01 rows=19567 width=8) (actual time=97.146..20274.526 rows=16067 loops=1) 
        -> Bitmap Heap Scan on weekly_baskets (cost=26501.11..62382.74 rows=33112 width=8) (actual time=97.049..15395.178 rows=34502 loops=1) 
          Recheck Cond: (menu_id = 344) 
          Heap Blocks: exact=12414 
          -> Bitmap Index Scan on index_weekly_baskets_on_user_id_and_menu_id (cost=0.00..26499.45 rows=33112 width=0) (actual time=94.135..94.135 rows=34514 loops=1) 
           Index Cond: (menu_id = 344) 
        -> Index Only Scan using uidx_cancellations_for_active on cancellations (cost=0.08..0.77 rows=1 width=4) (actual time=0.141..0.141 rows=1 loops=34502) 
          Index Cond: ((cancellable_id = weekly_baskets.id) AND (cancellable_type = 'WeeklyBasket'::text) AND (active = true)) 
          Heap Fetches: 12907 
       -> Index Only Scan using weekly_baskets_pkey on weekly_baskets weekly_baskets_meal_selections (cost=0.09..1.61 rows=1 width=4) (actual time=0.004..0.010 rows=1 loops=16067) 
        Index Cond: (id = weekly_baskets.id) 
        Heap Fetches: 16595 
     -> Index Only Scan using index_meal_selections_on_weekly_basket_id_and_meal_id on meal_selections (cost=0.09..0.14 rows=4 width=8) (actual time=0.508..0.737 rows=3 loops=16067) 
       Index Cond: (weekly_basket_id = weekly_baskets_meal_selections.id) 
       Heap Fetches: 47391 
Planning time: 1.568 ms 
Execution time: 32313.715 ms 

Очевидно, что это очень болезненно. Мне сложно с помощью LATERAL присоединиться для оптимизации этого запроса, но я не смог его обернуть.

+0

Когда вы в последний раз вы вакуумировали или пылесосили ваши столы? Есть несколько медленных вложенных циклов, но большие таймеры - это сканирование только по индексу (на 'meal_selections' и' cancelations'), а индекс кучи индекса - на 'weekly_baskets'. Возможно, что эти столы нуждаются в некотором внимании или что они просто очень большие. – jmelesky

+0

Последний вакуумный час около 6 дней назад был полным ручным вакуумом. Количество мертвых строк довольно низкое. Вы правы, 'meal_selections' имеет ~ 5m строк,' cancelations' имеет ~ 1.1m строк. –

+1

ваше соединение «weekly_baskets» «weekly_baskets_meal_selections», похоже, нигде не используется. Вы должны удалить его. Если я неправильно читаю ваш запрос, что возможно –

ответ

1

Попробуйте изменить свой поднабор влево и проверьте его на null, что должно помочь.

SELECT 
    SUM(weekly_baskets.servings/2) AS sum_weekly_baskets_servings_2, 
    meal_selections.meal_id AS meal_selections_meal_id 
FROM 
    "meal_selections" 
INNER JOIN 
    "weekly_baskets" "weekly_baskets_meal_selections" 
     ON "weekly_baskets_meal_selections"."id" = "meal_selections"."weekly_basket_id" 
INNER JOIN 
    "weekly_baskets" 
     ON "meal_selections"."weekly_basket_id" = "weekly_baskets"."id" 
LEFT JOIN "cancellations" on 
     "cancellations"."cancellable_id" = "weekly_baskets"."id" 
     AND "cancellations"."cancellable_type" = 'WeeklyBasket' 
     AND "cancellations"."active" = 't' 
WHERE 
    "weekly_baskets"."menu_id" = 344 
    AND "cancellations"."cancellable_id" is null 
GROUP BY 
    meal_selections.meal_id 
+0

Это не ускоряет запрос. –

+0

вы можете обновить свой вопрос с помощью анализа объяснений по этому новому предлагаемому запросу. Это кажется хорошей идеей (+1), потому что запросы NOT IN обычно немного медленны и, устраняя это, мы должны ускорить – e4c5

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