Performance 行级安全查询计划比相同的非RLS查询慢45倍

Performance 行级安全查询计划比相同的非RLS查询慢45倍,performance,postgresql,sql-execution-plan,row-level-security,Performance,Postgresql,Sql Execution Plan,Row Level Security,我在让查询计划器为支持行级安全性(RLS)的表编写良好的计划时遇到了一些问题。似乎只需要从启用了行级安全性的表连接到未启用行级安全性的表,就可以强制执行错误的计划,即使两个表上都有计划员应该能够使用的适当索引 有没有办法帮助规划者解决这个问题?或者当涉及RLS时,某些统计数据是否不可用 我尝试为不需要RLS的表启用RLS(使用(TRUE)添加一个带有的宽开放策略),其效果与不在该表中包含策略相同 DROP SCHEMA IF EXISTS foo CASCADE; CREATE SCHEMA f

我在让查询计划器为支持行级安全性(RLS)的表编写良好的计划时遇到了一些问题。似乎只需要从启用了行级安全性的表连接到未启用行级安全性的表,就可以强制执行错误的计划,即使两个表上都有计划员应该能够使用的适当索引

有没有办法帮助规划者解决这个问题?或者当涉及RLS时,某些统计数据是否不可用

我尝试为不需要RLS的表启用RLS(使用(TRUE)添加一个带有
的宽开放策略),其效果与不在该表中包含策略相同

DROP SCHEMA IF EXISTS foo CASCADE;
CREATE SCHEMA foo;

CREATE TABLE foo.bar AS
SELECT generate_series(1,10000000) AS id, md5(random()::text) AS descr, random() * 5 + 1 AS licflag;

CREATE TABLE foo.baz AS
SELECT generate_series(1,10000000) AS id, md5(random()::text) AS descr, random() * 5 + 1 AS licflag;

CREATE UNIQUE INDEX ON foo.bar (id);
CREATE INDEX ON foo.bar (licflag);

CREATE UNIQUE INDEX ON foo.baz (id);
CREATE INDEX ON foo.baz (licflag);

ANALYZE foo.bar;
ANALYZE foo.baz;

ALTER TABLE foo.bar ENABLE ROW LEVEL SECURITY;
--ALTER TABLE foo.baz ENABLE ROW LEVEL SECURITY;

DROP ROLE IF EXISTS restricted;
CREATE ROLE restricted NOINHERIT;

REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo FROM restricted;
GRANT restricted to current_user;
GRANT USAGE ON SCHEMA foo TO restricted;
GRANT SELECT ON ALL TABLES IN SCHEMA foo TO restricted;

CREATE POLICY restrict_foo ON foo.bar 
FOR SELECT TO restricted
USING (licflag < 3);

/*
CREATE POLICY restrict_foo ON foo.baz 
FOR SELECT TO restricted
USING (TRUE);
*/

EXPLAIN ANALYZE
SELECT * 
FROM foo.bar f1
JOIN foo.baz f2 ON f1.id = f2.id 
WHERE f2.id BETWEEN 500 AND 12000
AND f1.licflag < 3;

SET ROLE restricted;

EXPLAIN ANALYZE
SELECT * 
FROM foo.bar f1
JOIN foo.baz f2 ON f1.id = f2.id 
WHERE f2.id BETWEEN 500 AND 12000;
更新1:

我使用WHERE子句中的RLS谓词运行查询,如

EXPLAIN ANALYZE
SELECT *
FROM foo.bar f1
JOIN foo.baz f2 ON f1.id = f2.id
WHERE f1.id BETWEEN 500 AND 12000
AND f1.licflag < 3;
解释分析
挑选*
来自foo.bar f1
在f1.id=f2.id上连接foo.baz f2
其中f1.id介于500和12000之间
f1.1<3;
它产生了一个更好的查询计划。但是当我删除这个额外的谓词时,计划者保留了更好的计划。这让我觉得统计数据有问题。。有人知道如何在不重置整个数据库的统计信息的情况下手动触发统计信息更新吗?现在我自己在看博士后的文档

更新2:


尝试设置全局和表级统计限制,但无效。能够使用子选择而不是使用类似查询的联接来获得正确的查询计划,因此可以使用该技术作为解决方法。

相信这类似于“有人知道如何手动触发统计数据更新吗”-分析:玩统计目标似乎没有任何效果,不幸的是,你应该升级到最新的Postgres版本(截至撰写本文时,该版本为10.3)。Postgres 10在行级安全性能方面有一些重大改进,例如:
psql (9.5.3, server 9.5.4)
EXPLAIN ANALYZE
SELECT *
FROM foo.bar f1
JOIN foo.baz f2 ON f1.id = f2.id
WHERE f1.id BETWEEN 500 AND 12000
AND f1.licflag < 3;