Cal*_*mer 5 postgresql performance execution-plan row-level-security explain query-performance
我有一个看起来像这样的查询:
SELECT post.id, post.author_id, post.published_at, post.content
FROM post
WHERE post.group_id = 1
ORDER BY post.published_at DESC, post.id
LIMIT 5;
Run Code Online (Sandbox Code Playgroud)
(group_id, published_at DESC, id)当没有使用行级别安全性 (RLS) 策略时,此查询具有一个索引,该索引为其提供此查询计划。
Limit (cost=0.14..1.12 rows=5 width=143)
-> Index Scan using post_published_at on post (cost=0.14..15.86 rows=80 width=143)
Index Cond: (group_id = 1)
Run Code Online (Sandbox Code Playgroud)
然后我添加这个策略:
CREATE POLICY select_member_of ON post FOR SELECT USING
(EXISTS (SELECT 1
FROM group_member
WHERE group_member.account_id = current_setting('current_account_id', false)::INT AND
group_member.group_id = post.group_id));
Run Code Online (Sandbox Code Playgroud)
有在化合物主键group_member.account_id和group_member.group_id上group_member表中。
我希望Postgres的计划此查询为仅索引扫描的group_member,因为这两个group_member.account_id和group_member.group_id将被设定为恒定值。group_member.group_id由于WHERE post.group_id = 1上述SELECT查询中的条件,应该是常量。
事实上,当我将 RLS 策略内联到查询中时,这看起来正在发生,如下所示:
SELECT id, author_id, published_at, content
FROM post
WHERE group_id = 1 AND
(EXISTS (SELECT 1
FROM group_member
WHERE group_member.account_id = current_setting('current_account_id', false)::INT AND
group_member.group_id = post.group_id))
ORDER BY published_at DESC, id
LIMIT 5;
Run Code Online (Sandbox Code Playgroud)
我得到查询计划:
Limit (cost=0.30..1.85 rows=5 width=143)
-> Nested Loop Semi Join (cost=0.30..25.04 rows=80 width=143)
-> Index Scan using post_published_at on post (cost=0.14..15.86 rows=80 width=147)
Index Cond: (group_id = 1)
-> Materialize (cost=0.16..8.19 rows=1 width=4)
-> Index Only Scan using group_member_pkey on group_member (cost=0.16..8.18 rows=1 width=4)
Index Cond: ((account_id = (current_setting('current_account_id'::text, false))::integer) AND (group_id = 1))
Run Code Online (Sandbox Code Playgroud)
这就是我一直在寻找的。但是,当我使用真正的 RLS 策略运行查询时,查询计划变为:
Limit (cost=23.08..23.10 rows=5 width=143)
-> Sort (cost=23.08..23.28 rows=80 width=143)
Sort Key: post.published_at DESC, post.id
-> Subquery Scan on post (cost=8.92..21.75 rows=80 width=143)
-> Nested Loop Semi Join (cost=8.92..20.95 rows=80 width=147)
-> Bitmap Heap Scan on post post_1 (cost=8.76..11.76 rows=80 width=147)
Recheck Cond: (group_id = 1)
-> Bitmap Index Scan on post_published_at (cost=0.00..8.74 rows=80 width=0)
Index Cond: (group_id = 1)
-> Materialize (cost=0.16..8.20 rows=1 width=4)
-> Subquery Scan on group_member (cost=0.16..8.19 rows=1 width=4)
-> Index Only Scan using group_member_pkey on group_member group_member_1 (cost=0.16..8.18 rows=1 width=8)
Index Cond: ((account_id = (current_setting('current_account_id'::text, false))::integer) AND (group_id = 1))
Run Code Online (Sandbox Code Playgroud)
哪个更糟。
这是预期的行为吗?有没有办法为我内联 RLS 策略的版本获得相同的查询计划?
如果没有示例数据,\xe2\x80\x99 很难重现您的确切场景。
\n\n在我看来,你应该使政策中的表达尽可能简单。在你的情况下,这将是:
\n\nCREATE POLICY select_member_of ON post FOR SELECT USING (group_id IN (SELECT group_id\n FROM group_member\n WHERE account_id = current_setting('current_account_id', false)::INT));\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
605 次 |
| 最近记录: |