查询语言(SQL)函数中的通用执行计划

时间:2019-07-16 02:14:00

标签: postgresql

我正在尝试找出与参数化SQL函数的性能不佳相关的问题。该文档对PL / PGSQL函数中的执行计划相对比较清楚-查询计划者计划前5次执行,然后可以在同一会话后将执行计划进行缓存。

但是,我一直无法找到与SQL函数相关的类似文档,并且通过一些调查,似乎查询计划者总是使用通用计划。

这是一个简单的例子:

-- Postgres 11.1
-- Test table and some data
create table test (a int);
insert into test select 1 from generate_series(1,1000000);
insert into test values (2);
create index on test(a);
analyze test;

-- A SQL Function
create function test_f(val int, cnt out bigint) AS $$
SELECT count(*) FROM test where a = val;
$$ LANGUAGE SQL;

-- A similar PL/PGSQL Function
create function test_f_plpgsql (val int, cnt out bigint) AS $$
BEGIN
SELECT count(*) FROM test where a = val INTO cnt;
END
$$ LANGUAGE PLPGSQL;

-- Show plans
LOAD 'auto_explain';
SET auto_explain.log_analyze = on;
SET client_min_messages = log;
SET auto_explain.log_nested_statements = on;
SET auto_explain.log_min_duration = 0;

PL / PGSQL函数使用非通用计划,并且知道使用仅索引扫描。

select * from test_f_plpgsql(2);
LOG:  duration: 0.326 ms  plan:
Query Text: SELECT count(*) FROM test where a = val
Aggregate  (cost=4.45..4.46 rows=1 width=8) (actual time=0.180..0.202 rows=1 loops=1)
  ->  Index Only Scan using test_a_idx on test  (cost=0.42..4.44 rows=1 width=0) (actual time=0.096..0.135 rows=1 loops=1)
        Index Cond: (a = 2)
        Heap Fetches: 1
LOG:  duration: 1.250 ms  plan:
Query Text: select * from test_f_plpgsql(2);
Function Scan on test_f_plpgsql  (cost=0.25..0.26 rows=1 width=8) (actual time=1.116..1.152 rows=1 loops=1)
 cnt
-----
   1
(1 row)

另一方面,SQL函数使用通用计划,因此很难选择全表扫描。

select * from test_f(2);
LOG:  duration: 18.716 ms  plan:
Query Text:
SELECT count(*) FROM test where a = val;

Partial Aggregate  (cost=10675.01..10675.02 rows=1 width=8) (actual time=18.639..18.665 rows=1 loops=1)
  ->  Parallel Seq Scan on test  (cost=0.00..9633.34 rows=416667 width=0) (actual time=18.621..18.628 rows=0 loops=1)
        Filter: (a = $1)
        Rows Removed by Filter: 273008
LOG:  duration: 28.304 ms  plan:
Query Text:
SELECT count(*) FROM test where a = val;

Partial Aggregate  (cost=10675.01..10675.02 rows=1 width=8) (actual time=28.234..28.248 rows=1 loops=1)
  ->  Parallel Seq Scan on test  (cost=0.00..9633.34 rows=416667 width=0) (actual time=28.199..28.208 rows=1 loops=1)
        Filter: (a = $1)
        Rows Removed by Filter: 129222
LOG:  duration: 45.913 ms  plan:
Query Text:
SELECT count(*) FROM test where a = val;

Finalize Aggregate  (cost=11675.22..11675.23 rows=1 width=8) (actual time=42.370..42.377 rows=1 loops=1)
  ->  Gather  (cost=11675.01..11675.22 rows=2 width=8) (actual time=42.288..45.787 rows=3 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Partial Aggregate  (cost=10675.01..10675.02 rows=1 width=8) (actual time=29.579..29.597 rows=1 loops=3)
              ->  Parallel Seq Scan on test  (cost=0.00..9633.34 rows=416667 width=0) (actual time=29.553..29.560 rows=0 loops=3)
                    Filter: (a = $1)
                    Rows Removed by Filter: 333333
LOG:  duration: 47.128 ms  plan:
Query Text: select * from test_f(2);
Function Scan on test_f  (cost=0.25..0.26 rows=1 width=8) (actual time=47.058..47.073 rows=1 loops=1)
 cnt
-----
   1
(1 row)

是否有一种方法可以强制SQL函数使用非泛型计划?

0 个答案:

没有答案