本文讨论 PostgreSQL 17 中“stack depth limit exceeded”错误的成因与修复。作者实测四种情形:自更新触发器、自调用函数、通过函数读取自身表的行级安全策略、超长表达式。前三种属无限递归,调高 max_stack_depth 只能延后报错;超长表达式有界,提高上限可放行。修复方法:触发器改用 BEFORE 修改行、函数加基准条件、策略避免自引用;扁平 OR/AND 链和 IN 列表不易触发。
PostgreSQL 17/18 不支持 CREATE POLICY IF NOT EXISTS 或 CREATE OR REPLACE POLICY,可重复迁移策略有三种:一是在同一事务中先 DROP POLICY IF EXISTS 再 CREATE POLICY,能确保定义正确,但 DROP 会取 ACCESS EXCLUSIVE 锁,事务外执行会出现无策略空窗,FORCE 下所有租户查不到数据;二是用 DO 块查 pg_policies 再创建,适合只建不改的策略,并发部署需加 advisory 锁;三是仅改表达式或角色时用 ALTER POLICY,但同样取 ACCESS EXCLUSIVE 锁且策略不存在时会失败。建议配合 lock_timeout。
PostgreSQL 17 中,行级安全策略读取其保护的同一张表时会报“infinite recursion detected in policy”。基于百万行数据的实测显示,六种修复方案中,会话变量存租户最快(0.09 毫秒),STABLE 函数返回数组配合 = any 次之,VOLATILE 函数逐行调用慢至 6.6 秒。建议使用 BYPASSRLS 角色、限定 FOR SELECT 并撤销公开执行权限。
基于 PostgreSQL 17.11 实测,分析“new row violates row-level security policy”错误:该错误有四种形式、六类成因,包括租户不匹配、未设置租户、缺少插入策略、RETURNING 或 ON CONFLICT 需要 SELECT 策略、限制性策略拒绝、upsert 命中无权更新的行。排查时应检查当前租户设置、pg_policies 中对应命令与角色的策略,以及语句是否读取该行。
PostgreSQL 按租户列表分区时,若仅靠行级安全策略过滤租户,规划器无法预知租户,需扫描全部分区。实测1000租户查询从0.25毫秒增至77毫秒,3000租户达241毫秒,并产生数千锁,32并发下大量报共享内存不足。修复方法:查询中显式加tenant_id条件;添加租户改用CREATE TABLE加ATTACH PARTITION。
实测PostgreSQL 17多租户审计日志触发器开销:2万次单行更新每次增加32微秒;10万行批量更新慢3.6至4.4倍。语句触发器配转换表比行触发器快约两成,但仅限AFTER且不能指定列。只存变更列可使日志缩小五倍,但比较更耗CPU。用行级安全策略限制租户只能读自己的日志,应用角色仅可SELECT和INSERT,日志追加不可改。
实测 PostgreSQL 17 行级安全策略的性能开销:简单等值策略几乎无成本;调用 PL/pgSQL 等不可内联函数的策略会退化为全表扫描,耗时近 2 秒;成员子查询策略每查询约 80 毫秒。lower()、LIKE 等非 leakproof 函数会阻止索引使用,使大租户查询从 0.2 毫秒增至 45 毫秒。建议将辅助函数声明为 STABLE PARALLEL SAFE,使用生成列或 leakproof 操作符,并提前解析租户归属。
Supabase发布了实时广播和在线状态的授权功能,允许用户实时发送和接收消息。此版本引入了使用行级安全策略的授权功能,用户可以创建策略来控制对广播和在线状态频道的访问。文章还介绍了如何在频道上启用授权,并提供了高级示例。实时授权通过在实时消息表上运行查询并确定用户的策略来实现,该方法性能良好且延迟低。还提到了Postgres Changes支持。Supabase正在寻求反馈以改进实时授权。
Supabase推出了新的AI助手,简化了行级安全策略的创建。新RLS编辑器结合SQL和AI,帮助开发者快速编写安全策略。用户可以在Studio中选择不同的Postgres角色,测试安全策略的影响,并通过实时检查器调试实时消息。这些更新旨在提升用户体验,加速开发过程。
PostgreSQL 15增加了逻辑复制的保障措施,确保订阅所有者具有完成所需操作的必要权限。现在,订阅的APPLY进程将使用订阅所有者的权限而非超级用户权限运行。这个变化可以防止安全漏洞并限制了带有行级安全策略的表的复制。订阅所有者不再可以规避RLS策略,但超级用户、具有'bypassrls'权限的角色和目标表所有者仍然可以绕过RLS策略进行复制。计划允许非超级用户角色创建订阅并允许在该角色的权限范围内进行逻辑复制。
完成下面两步后,将自动完成登录并继续当前操作。