У меня есть головоломка производительности Postgresql (версия 9.4). У меня есть функция (prevd
), объявленная как STABLE
(см. Ниже). Когда я запускаю эту функцию в константе в пункте where
, она вызывается несколько раз - вместо одного. Если я правильно понимаю документацию postgres, запрос должен быть оптимизирован для вызова prevd
только один раз.Postgres: Функция STABLE, называемая несколько раз на константе
Стабильная функция не может изменять базу данных и гарантированно возвращает те же результаты, приведенные одни и те же аргументы для всех строк в одном операторе
Почему не оптимизировать вызовы prevd
в этом случае ? Я не ожидаю, что prevd
будет вызываться один раз для всех последующих запросов, используя prevd
по тому же аргументу (например, он был IMMUTABLE). Я ожидаю, что Postgres, чтобы создать план для моего запроса только с одним вызовом prevd('2015-12-12')
Вы можете найти код ниже:
Схема
create table somedata(d date, number double precision);
create table dates(d date);
insert into dates
select generate_series::date
from generate_series('2015-01-01'::date, '2015-12-31'::date, '1 day');
insert into somedata
select '2015-01-01'::date + (random() * 365 + 1)::integer, random()
from generate_series(1, 100000);
create or replace function prevd(date_ date)
returns date
language sql
stable
as $$
select max(d) from dates where d < date_;
$$
медленных запросов
select avg(number) from somedata where d=prevd('2015-12-12');
Плохой план запроса t он выше запрос
Aggregate (cost=28092.74..28092.75 rows=1 width=8) (actual time=3532.638..3532.638 rows=1 loops=1)
Output: avg(number)
-> Seq Scan on public.somedata (cost=0.00..28091.43 rows=525 width=8) (actual time=10.210..3532.576 rows=282 loops=1)
Output: d, number
Filter: (somedata.d = prevd('2015-12-12'::date))
Rows Removed by Filter: 99718
Planning time: 1.144 ms
Execution time: 3532.688 ms
(8 rows)
Performance
Запрос выше, на моей машине работает около 3.5с. После изменения prevd
на IMMUTABLE он меняется на 0.035.
Возможный дубликат [Почему PostgreSQL вызова мои STABLE/непреложных функции несколько раз?] (HTTP: // stackoverflow.com/questions/8529690/why-is-postgresql-calling-my-stable-immutable-function-multiple-times) - тестовый пример в вопросе отличается, но ответ также охватывает ваш случай. – IMSoP
Мой запрос вызывает функцию STABLE на константе. Запрос по указанному вопросу вызывает функцию IMMUTABLE для не-costant value (по крайней мере, не напрямую) –
Взгляните на * ответ * на связанный вопрос, а не на сам вопрос. Он охватывает почти любую комбинацию стабильного/неизменяемого и постоянного/непостоянного аргумента, в том числе точно так же, как и у вас: «Когда' где test_multi_calls1 (30)! = Num' переписывание запроса произойдет для неизменяемых, но не для просто стабильных функций ». – IMSoP