Стабильные функции PostgreSQL в запросе

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

Это две функции funcFast а также funcList, funcFast может вернуть быстрый результат, если таблица должна быть отфильтрована funcList или нет. funcList вернуть список разрешенных идентификаторов. Я пометил функции как СТАБИЛЬНЫЕ, но они работают не так быстро, как я ожидаю:)

Я создаю пару примеров функций:

CREATE OR REPLACE FUNCTION funcFastPlPgSql(res boolean)
returns boolean as $$
    begin return res; end
$$ language plpgsql stable;

CREATE OR REPLACE FUNCTION funcList(cnt int)
returns setof integer as $$
    select generate_series(1, cnt)
$$ language sql stable;

И тесты.

Случай 1. Фильтр только по быстрой работе функции ОК:

explain analyze
with obs as (select generate_series(1, 1000000) as id)
select count(*) from obs 
where funcFastPlPgSql(true)

План запроса:

Aggregate  (cost=27.76..27.77 rows=1 width=8) (actual time=573.258..573.259 rows=1 loops=1)
  CTE obs
    ->  Result  (cost=0.00..5.01 rows=1000 width=4) (actual time=0.006..114.327 rows=1000000 loops=1)
  ->  Result  (cost=0.25..20.25 rows=1000 width=0) (actual time=0.038..489.942 rows=1000000 loops=1)
        One-Time Filter: funcfastplpgsql(true)
        ->  CTE Scan on obs  (cost=0.25..20.25 rows=1000 width=0) (actual time=0.012..392.504 rows=1000000 loops=1)
Planning time: 0.184 ms
Execution time: 576.177 ms

Случай 2. Фильтр только по медленной функции тоже работает нормально:

explain analyze
with obs as (select generate_series(1, 1000000) as id)
select count(*) from obs 
where  id in (select funcList(1000))

План запроса:

Aggregate  (cost=62.26..62.27 rows=1 width=8) (actual time=469.344..469.344 rows=1 loops=1)
  CTE obs
    ->  Result  (cost=0.00..5.01 rows=1000 width=4) (actual time=0.006..106.144 rows=1000000 loops=1)
  ->  Hash Join  (cost=22.25..56.00 rows=500 width=0) (actual time=1.566..469.202 rows=1000 loops=1)
        Hash Cond: (obs.id = (funclist(1000)))
        ->  CTE Scan on obs  (cost=0.00..20.00 rows=1000 width=4) (actual time=0.009..359.580 rows=1000000 loops=1)
        ->  Hash  (cost=19.75..19.75 rows=200 width=4) (actual time=1.548..1.548 rows=1000 loops=1)
              Buckets: 1024  Batches: 1  Memory Usage: 44kB
              ->  HashAggregate  (cost=17.75..19.75 rows=200 width=4) (actual time=1.101..1.312 rows=1000 loops=1)
                    Group Key: funclist(1000)
                    ->  Result  (cost=0.00..5.25 rows=1000 width=4) (actual time=0.058..0.706 rows=1000 loops=1)
Planning time: 0.141 ms
Execution time: 472.183 ms

Случай 3. Но тогда две функции объединены, я ожидаю, что лучший случай должен быть близок к [случаю 1], а худший случай должен быть близок к [случаю 2], но:

explain analyze
with obs as (select generate_series(1, 1000000) as id)
select count(*) from obs
where funcFastPlPgSql(true) or id in (select funcList(1000))

План запроса:

Aggregate  (cost=286.93..286.94 rows=1 width=8) (actual time=1575.775..1575.775 rows=1 loops=1)
  CTE obs
    ->  Result  (cost=0.00..5.01 rows=1000 width=4) (actual time=0.008..131.372 rows=1000000 loops=1)
  ->  CTE Scan on obs  (cost=7.75..280.25 rows=667 width=0) (actual time=0.035..1468.007 rows=1000000 loops=1)
        Filter: (funcfastplpgsql(true) OR (hashed SubPlan 2))
        SubPlan 2
          ->  Result  (cost=0.00..5.25 rows=1000 width=4) (never executed)
Planning time: 0.100 ms
Execution time: 1578.624 ms

Что мне здесь не хватает? Почему запрос с двумя функциями вместе выполняется намного дольше и как это исправить?

0 ответов

Другие вопросы по тегам