You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL RLS策略中函数过滤为何无法利用索引提升性能?

RLS策略中USING (tenant_id = get_tenant_id())无法利用索引过滤的原因及解决方法

问题现象

仅依赖RLS策略实现租户数据隔离时,执行SELECT count(*) FROM people的性能极差:

SET app.tenant_id = 2; SET ROLE user;
EXPLAIN ANALYZE SELECT count(*) FROM people;
RESET ROLE; RESET app.tenant_id;

执行计划显示数据库先扫描全量索引数据,再通过Filter过滤非目标租户的数据:

Aggregate  (cost=32570.08..32570.09 rows=1 width=8) (actual time=62.855..62.856 rows=1 loops=1)
  ->  Index Only Scan using index_people_on_tenant_id on people  (cost=0.29..32429.13 rows=56381 width=0) (actual time=58.639..62.642 rows=6000 loops=1)
        Filter: (tenant_id = get_tenant_id())
        Rows Removed by Filter: 101125
        Heap Fetches: 57059
Planning Time: 1.979 ms
Execution Time: 65.704 ms

手动添加WHERE tenant_id = 2后,性能显著提升,执行计划显示数据库直接利用索引条件定位目标租户数据:

SET app.tenant_id = 2; SET ROLE user;
EXPLAIN ANALYZE SELECT count(*) FROM people where tenant_id = 2;
RESET ROLE; RESET app.tenant_id;
Aggregate  (cost=1818.55..1818.56 rows=1 width=8) (actual time=13.079..13.080 rows=1 loops=1)
  ->  Index Only Scan using index_people_on_tenant_id on people  (cost=0.29..1810.77 rows=3112 width=0) (actual time=0.467..12.348 rows=6000 loops=1)
        Index Cond: (tenant_id = 2)
        Filter: (tenant_id = get_tenant_id())
        Heap Fetches: 11826
Planning Time: 1.867 ms
Execution Time: 15.641 ms

核心原因

问题出在get_tenant_id()函数的稳定性属性:

  • PostgreSQL中,PL/pgSQL函数默认属性为VOLATILE(易变),数据库认为该函数每次调用返回结果可能不同,无法在查询规划阶段确定其返回值。
  • 因此RLS策略中的USING (tenant_id = get_tenant_id())无法被规划器转换为可用于索引匹配的等值条件,只能在扫描完所有索引条目后逐行调用函数过滤。
  • 手动添加的WHERE tenant_id = 2是明确常量值,规划器可直接用它作为索引条件,快速定位目标数据。

解决方案

将get_tenant_id()函数属性改为STABLE(稳定)——同一个会话中app.tenant_id设置后不会改变,函数返回值在会话周期内固定:

CREATE OR REPLACE FUNCTION get_tenant_id() RETURNS BIGINT AS $$
BEGIN
  RETURN NULLIF(current_setting('app.tenant_id', TRUE), '')::BIGINT;
END;
$$ LANGUAGE plpgsql STABLE;

修改后,查询规划器会在会话开始时解析函数返回值,将RLS条件转换为与手动WHERE子句等价的索引匹配条件,大幅提升查询性能。

内容的提问来源于stack exchange,提问作者George Morris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 23:47:24