eni*_*njo 8 sql database postgresql row-level-security
我正在使用PostgreSQL 10.1,直奔主题...
假设我有一个TABLE:
CREATE TABLE public.document (
id uuid PRIMARY KEY,
title text,
content text NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
连同上面的GIN INDEX:
CREATE INDEX document_idx ON public.document USING GIN(
to_tsvector(
'english',
content || ' ' || COALESCE(title, '')
)
);
Run Code Online (Sandbox Code Playgroud)
还有一个基本的全文搜索查询:
SELECT * FROM public.document WHERE (
to_tsvector(
'english',
content || ' ' || COALESCE(title, '')
) @@ plainto_tsquery('english', fulltext_search_documents.search_text)
)
Run Code Online (Sandbox Code Playgroud)
无论public.document表大小如何,查询都非常快(您已经知道了)!规划器使用 INDEX,一切都很好。
现在我通过RLS (Row Level Security)介绍一些基本的访问控制,首先我启用它:
ALTER TABLE public.document ENABLE ROW LEVEL SECURITY;
Run Code Online (Sandbox Code Playgroud)
然后我添加策略:
CREATE POLICY document_policy ON public.document FOR SELECT
USING (EXISTS (
SELECT 1 FROM public.user WHERE (is_current_user) AND ('r' = ANY(privileges))
));
Run Code Online (Sandbox Code Playgroud)
为了简单起见,is_current_user是另一个查询,它会准确地检查它。
现在全文搜索查询被document_policy 查询扁平化,这样规划器执行Seq Scan而不是Index Scan导致查询速度降低 300 倍!
我认为这个问题很明显,我该如何解决这个问题,以便全文搜索查询保持快速?
提前致谢!
eni*_*njo 11
我从发布时就解决了这个问题......任何遇到这个问题的人,我都是这样做的:
我的解决方案是拥有一个包含 propper 查询的私有 SECURITY DEFINER“包装器”函数和另一个调用私有函数和需要访问控制的表的公共函数。INNER JOINS
所以在上面的特定情况下,它会是这样的:
CREATE FUNCTION private.filter_document() RETURNS SETOF public.document AS
$$
SELECT * FROM public.document WHERE (
to_tsvector(
'english',
content || ' ' || COALESCE(title, '')
) @@ plainto_tsquery('english', fulltext_search_documents.search_text)
)
$$
LANGUAGE SQL STABLE SECURITY DEFINER;
----
CREATE FUNCTION public.filter_document() RETURNS SETOF public.document AS
$$
SELECT filtered_d.* FROM private.filter_documents() AS filtered_d
INNER JOIN public.document AS d ON (d.id = filtered_d.id)
$$
LANGUAGE SQL STABLE;
Run Code Online (Sandbox Code Playgroud)
由于我使用的是Postgraphile(顺便说一句,这真是太棒了!),我能够省略对私有模式的自省,使“危险”功能无法访问!通过适当的安全实现,最终用户只会看到最终的 GraphQL 模式,完全从外部世界中删除Postgres。
这很有效! 直到最近Postgres 10.3 发布并修复它时,才不再需要这个 hack。
另一方面,我的 RLS 策略非常复杂,嵌套并且非常深入。它们再次运行的表也非常大(总共大约有 50,000 多个条目用于运行 RLS)。即使使用超级复杂和嵌套的策略,我也设法将性能保持在合理的范围内。
使用 RLS 时,请记住以下几点:
INDEXESSTABLE高的COST(就像@mkurtz 指出的那样);或者是IMMUTABLEEXPLAIN ANALYZE并尝试尽可能优化它希望你们发现这些信息和我一样有用!
| 归档时间: |
|
| 查看次数: |
1474 次 |
| 最近记录: |