Инкапсуляция запроса Postgres делает его чрезвычайно медленным - PullRequest
5 голосов
/ 20 августа 2010

У меня есть запрос, который выполняется около 5 секунд на Postgres 8.4. Он выбирает данные из представления, объединенного с некоторыми другими таблицами, но также использует оконную функцию lag () , т. Е.

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v
JOIN othertables USING (...)
WHERE ...

Для удобства я создал новый вид, который просто имеет

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v

, а затем ВЫБРАТЬ из этого, используя все другие СОЕДИНЕНИЯ и фильтры, как и раньше. К моему удивлению, этот запрос не завершается за 12 минут (я остановил его в тот момент). Очевидно, Postgres выбрал другой план выполнения. Как мне заставить его этого не делать, т.е. использовать тот же план, что и в исходном запросе? Я бы подумал, что представление не должно изменять план выполнения, но, видимо, это так.

Редактировать: более того, я обнаружил, что даже если я скопирую содержимое первого представления во второе, оно все еще не возвращается.

Редактировать 2: ОК, я достаточно упростил запрос, чтобы опубликовать планы.

Использование представления (это не возвращает в разумные сроки):

Subquery Scan sp  (cost=5415201.23..5892463.97 rows=88382 width=370)
  Filter: (((sp.ticker)::text ~~ 'Some Ticker'::text) AND (sp.price_date >= '2010-06-01'::date))
  ->  WindowAgg  (cost=5415201.23..5680347.20 rows=53029193 width=129)
        ->  Sort  (cost=5415201.23..5441715.83 rows=53029193 width=129)
              Sort Key: sp.stock_id, sp.price_date
              ->  Hash Join  (cost=847.87..1465139.61 rows=53029193 width=129)
                    Hash Cond: (sp.stock_id = s.stock_id)
                    ->  Seq Scan on stock_prices sp  (cost=0.00..1079829.20 rows=53029401 width=115)
                    ->  Hash  (cost=744.56..744.56 rows=29519 width=18)
                          ->  Seq Scan on stocks s  (cost=0.00..744.56 rows=29519 width=18)

Вывод оконной функции из представления и вставка в сам запрос (это возвращает мгновенно):

WindowAgg  (cost=34.91..34.95 rows=7 width=129)
  ->  Sort  (cost=34.91..34.92 rows=7 width=129)
        Sort Key: sp.stock_id, sp.price_date
        ->  Nested Loop  (cost=0.00..34.89 rows=7 width=129)
              ->  Index Scan using stocks_ticker_unique on stocks s  (cost=0.00..4.06 rows=1 width=18)
                    Index Cond: ((ticker)::text = 'Some Ticker'::text)
                    Filter: ((ticker)::text ~~ 'Some Ticker'::text)
              ->  Index Scan using stock_prices_id_date_idx on stock_prices sp  (cost=0.00..30.79 rows=14 width=115)
                    Index Cond: ((sp.stock_id = s.stock_id) AND (sp.price_date >= '2010-06-01'::date))

Так что кажется, что в медленном случае он пытается применить оконную функцию сначала ко всем данным, а затем отфильтровать их, что, вероятно, является проблемой. Я не знаю, почему он это делает.

Ответы [ 2 ]

2 голосов
/ 14 мая 2011

Ваше различие между этими двумя планами связано с объединением. Это предотвращает использование плана вложенного цикла. Когда вы используете совокупность в своем представлении, вы попадаете в этот неблагоприятный сценарий.

Это, например, почти всегда приводит к плану слияния или объединения хэшей для двух таблиц, за которым следует сортировка top-n:

select foo.*
from foo
join (select bar.* from bar group by bar.field) as bar on foo.field = bar.field
where ...
order by bar.field
limit 10;
0 голосов
/ 03 марта 2012

Возможно, вы могли бы рассмотреть возможность использования Common Table Expression (CTE) вместо представления. Я могу помочь сделать запрос более понятным, подобно использованию представления, но, похоже, не влияет на план выполнения таким же образом.

У меня была похожая проблема в этом вопросе , и использование CTE вместо представления сделало план выполнения намного более эффективным.

...