UDF结果缓存

UDF 结果缓存(Result Cache)特性表示在一个计划执行周期(即单条语句的执行周期)内,支持共享确定性自定义函数(UDF, User Defined Function)的调用结果。通过节省过程语言引擎的调用和运行开销,大幅提高UDF的执行性能。

IMMUTABLE和STABLE函数在同一次计划的执行过程中,能够保证相同的参数返回相同的结果。通过缓存函数参数对应的执行结果,在使用相同参数反复调用时,不必再调用过程语言引擎,可以大幅提升函数返回结果的速度。

此功能受GUC参数 enable_func_cache 选项控制。开启此选项后,允许确定性函数使用结果缓存以提升非首次运行UDF的性能。

适用场景与限制

UDF结果缓存使用时,用户需要确认函数在同一次计划的执行过程中,相同的入参返回相同的结果,才能给函数增加RESULT_CACHE属性,使用该特性。否则执行可能出现错误的结果。

UDF结果缓存在函数传入的参数值重复率高的场景下,能够起到较好的性能提升效果;在函数传入的参数值重复率不高的场景下,反而可能引起性能的劣化。

  • 适用场景

  • 支持缓存的参数类型:

    • 整型:SMALLINT、INT、BIGINT
    • 浮点:FLOAT、DOUBLE PRECISION
    • 字符串:CHAR、VARCHAR、TEXT、VARCHAR2
    • 数值:NUMERIC
    • 时间:DATE、TIME、TIMESTAMP、TIMESTAMPTZ
    • 其他:BOOL、NVARCHAR2
  • 非适用场景

  • 不支持结果缓存的函数类型:

    • 使用内置过程语言(INTERNAL、C、SQL)的函数。
    • RESULT_CACHE 属性为 FALSE 的函数。
    • 含有非 IN 入参的函数。
    • 函数返回结果集、存在可变参数、存在不支持的参数类型。
    • 具有 VOLATILE 属性的函数、聚集函数、窗口函数、存在安全定义或参数数量不一致的函数。
    • 函数中存在子程序、自治事务。
    • 参数超过16个的函数。
    • 不支持结果缓存的场景:

    • 除SELECT语句外的语句类型。

    • 开启了SMP并行查询。
    • 传入的参数值超过 127 个字符。
    • 单条语句内UDF数量超过14个,第14个以后的函数不进行缓存。

示例

  1. 创建测试表,构造并插入测试数据。由于测试表tt_result_cache中的数据量较大且存在很多重复的数据,因此更容易体现出开启结果缓存后的优化效果。

``` 1. CREATE TABLE tt_result_cache( 2. id int, 3. col_bool bool, 4. col_smallint smallint, 5. col_int int, 6. col_bigint bigint, 7. col_float float, 8. col_double_precision double precision, 9. col_char char(20), 10. col_varchar varchar(20), 11. col_varchar2 varchar2(20), 12. col_timestamp timestamp, 13. col_numeric numeric, 14. col_text text 15. );

  1. INSERT INTO tt_result_cache VALUES(
  2. generate_series(1,10000),
  3. false,
  4. generate_series(1,10000)%5,
  5. generate_series(1,10000)%5,
  6. generate_series(1,10000)%5,
  7. generate_series(1,10000)%5,
  8. generate_series(1,10000)%5,
  9. random()*10%10||'_txt',
  10. random()*10%10||'_txt',
  11. random()*10%10||'_txt',
  12. '2024-11-22 16:36:45',
  13. generate_series(1,10000)%5,
  14. random()*10%10||'_txt'
  15. ); ```
  16. 分别创建具有或不具有RESULT_CACHE标记的确定性函数。

  17. 创建无RESULT_CACHE标记的函数:

    1. CREATE OR REPLACE FUNCTION func_smallint(p SMALLINT) RETURNS SMALLINT AS $$ 2. BEGIN 3. IF p = 1 THEN 4. raise notice 'param:%',p; 5. END IF; 6. RETURN p+1; 7. END; 8. $$ LANGUAGE PLPGSQL STABLE; - 创建具有RESULT_CACHE标记的函数:

    1. CREATE OR REPLACE FUNCTION func_smallint_cache(p SMALLINT) RETURNS SMALLINT AS $$ 2. BEGIN 3. IF p = 1 THEN 4. raise notice 'param:%',p; 5. END IF; 6. RETURN p+1; 7. END; 8. $$ LANGUAGE PLPGSQL STABLE RESULT_CACHE; 3. 开启 GUC 参数 enable_func_cache。

1. set enable_func_cache=on; 4. 分别查看两个函数的执行时间。

1. EXPLAIN (COSTS OFF, ANALYZE) SELECT col_smallint,func_smallint(col_smallint) FROM tt_result_cache; 2. EXPLAIN (COSTS OFF, ANALYZE) SELECT col_smallint,func_smallint_cache(col_smallint) FROM tt_result_cache;

返回结果如下,可见在启用了UDF结果缓存特性后,具有RESULT_CACHE的确定性函数在(非首次)执行时够显著提升执行效率:

``` 1. QUERY PLAN 2. --------------------------------------------------------------------------- 3. Seq Scan on tt_result_cache (actual time=1.452..81.903 rows=10000 loops=1) 4. Total runtime: 83.118 ms 5. (2 rows)

  1. QUERY PLAN

  2. Seq Scan on tt_result_cache (actual time=1.087..7.730 rows=10000 loops=1)
  3. Total runtime: 9.407 ms
  4. (2 rows) ```