1

我有一些由几个表组成的数据模型,我需要过滤它们。

它是两个函数funcFastfuncListfuncFast可以快速返回结果是表是否需要过滤funcListfuncList返回允许的 ID 列表。我将函数标记为 STABLE,但它们的运行速度没有我预期的那么快:)

我创建了几个示例函数:

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

我在这里缺少什么?为什么使用两个一起查询的函数运行时间更长,如何解决?

4

0 回答 0