将 SQL 函数标记为 LEAKPROOF 是否有任何性能优势?

Eva*_*oll 6 postgresql performance functions

PostgreSQL 有一个属性LEAKRPOOF,你可以用它来声明一个函数,

LEAKPROOF表示该函数没有副作用。除了返回值外,它不显示有关其参数的任何信息。例如,对于某些参数值而不是其他参数值抛出错误消息的函数,或者在任何错误消息中包含参数值的函数都不是防漏的。这会影响系统对使用该security_barrier选项创建的视图或启用了行级安全性的表执行查询的方式。系统将在用户提供的包含非防漏功能的查询本身的任何条件之前强制执行安全策略和安全屏障视图中的条件,以防止数据意外暴露。标记为防漏的函数和操作符被认为是可信的,并且可以在安全策略和安全屏障视图的条件之前执行。

文件继续说,

查询计划器在处理没有副作用的函数时具有更大的灵活性。此类函数称为LEAKPROOF,并且包括许多简单、常用的运算符,例如许多相等运算符。查询规划器可以安全地允许在查询执行过程中的任何点评估此类函数,因为在用户不可见的行上调用它们不会泄漏有关不可见行的任何信息。此外,不接受参数或未从安全屏障视图传递任何参数的函数不必标记为LEAKPROOF被推下,因为它们永远不会从视图接收数据。相比之下,根据作为参数接收到的值可能抛出错误的函数(例如在溢出或被零除时抛出错误的函数)不是防漏的,并且可以提供关于看不见的行的重要信息如果在安全视图的行过滤器之前应用。

是下面的LEAKRPOOF函数

CREATE FUNCTION foo_leakproof(bar int)
RETURNS int AS $$
  SELECT bar;
$$
IMMUTABLE LEAKPROOF
LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)

曾经有过不同的计划,或者它是否使用与LEAKPROOF缺乏替代方案不同的运行时配置文件运行,

CREATE FUNCTION foo_leaky(bar int)
RETURNS int AS $$
  SELECT bar;
$$
IMMUTABLE
LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)

Eva*_*oll 4

在最简单的情况下,这两个性能配置文件之间似乎没有区别,

CREATE TABLE t1 AS
  SELECT x::int FROM generate_series(1,1e6) AS gs(x);

CREATE VIEW v1 AS TABLE t1;

CREATE VIEW v2 WITH (security_barrier) 
  AS TABLE t1;

-- BASE TABLE
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM t1;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM t1;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM t1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM t1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM t1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM t1;

-- VIEW
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v1;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v1;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v1;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v1;

-- VIEW with SECURITY_BARRIER
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v2;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v2;
EXPLAIN ANALYZE SELECT foo_leaky(x) FROM v2;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v2;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v2;
EXPLAIN ANALYZE SELECT foo_leakproof(x) FROM v2;
Run Code Online (Sandbox Code Playgroud)

这些都是 100-110 毫秒。性能上没有区别

但是改变要使用的功能

CREATE FUNCTION foo_leakproof(bar int)
RETURNS int AS $$
  SELECT bar+1;
$$
IMMUTABLE LEAKPROOF
LANGUAGE sql;

CREATE FUNCTION foo_leaky(bar int)
RETURNS int AS $$
  SELECT bar+1;
$$
IMMUTABLE
LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)

将使所有调用变慢,但在有和没有 的版本上v2(我们的观点有security_barrier)上的调用要慢得多(慢 2 倍)LEAKPROOF。这也与文档security_barrier一致,

使用 security_barrier 创建的视图的性能可能比不使用此选项创建的视图差得多。一般来说,没有办法避免这种情况:如果可能危及安全,则必须拒绝尽可能最快的计划。因此,默认情况下不启用此选项。

;tldr LEAKPROOF似乎永远不会使查询变慢。然而,在我的测试中,它也没有让它们变得更快。也许它能够更好地优化带有 的视图上的查询security_barrier,但我还没有创建该环境。security_barrier极大地减慢了视图速度,并且只应在需要时使用。

使用 PostgreSQL 10.4 完成的基准测试。