调试性能问题
使用 Postgres 执行计划器调试运行缓慢的查询。
explain() 是一个提供 Postgres EXPLAIN 执行计划的方法。它是调试慢查询和理解 Postgres 将如何执行给定查询的强大工具。此功能适用于任何查询,包括通过 rpc() 或写操作发起的查询。
启用 explain()#
explain() 默认情况下是禁用的,以保护数据库结构和操作的敏感信息。我们建议在非生产环境中使用的 explain()。运行以下 SQL 以启用 explain()
1-- enable explain2alter role authenticator3set pgrst.db_plan_enabled to 'true';45-- reload the config6notify pgrst, 'reload config';使用 explain()#
要获取查询的执行计划,可以将 explain() 方法链接到 Supabase 查询
1const { data, error } = await supabase2 .from('instruments')3 .select()4 .explain()示例数据#
为了说明,考虑以下 instruments 表的设置
1create table instruments (2 id int8 primary key,3 name text4);56insert into books7 (id, name)8values9 (1, 'violin'),10 (2, 'viola'),11 (3, 'cello');预期响应#
响应通常如下所示
1Aggregate (cost=33.34..33.36 rows=1 width=112)2 -> Limit (cost=0.00..18.33 rows=1000 width=40)3 -> Seq Scan on instruments (cost=0.00..22.00 rows=1200 width=40)默认情况下,执行计划以 TEXT 格式返回。但是,您也可以通过指定 format 参数以 JSON 格式获取它。
生产环境中使用预请求保护#
如果您需要在生产环境中启用 explain(),请确保通过限制对 explain() 功能的访问来保护您的数据库。您可以通过使用基于 IP 地址过滤请求的预请求函数来做到这一点
1create or replace function filter_plan_requests()2returns void as $$3declare4 headers json := current_setting('request.headers', true)::json;5 client_ip text := coalesce(headers->>'cf-connecting-ip', '');6 accept text := coalesce(headers->>'accept', '');7 your_ip text := '123.123.123.123'; -- replace this with your IP8begin9 if accept like 'application/vnd.pgrst.plan%' and client_ip != your_ip then10 raise insufficient_privilege using11 message = 'Not allowed to use application/vnd.pgrst.plan';12 end if;13end; $$ language plpgsql;14alter role authenticator set pgrst.db_pre_request to 'filter_plan_requests';15notify pgrst, 'reload config';pgrst.db_pre_request 配置仅适用于 Data API (PostgREST)。它不适用于 Realtime、Storage 或其他 Supabase 产品。
如果您正在使用 db_pre_request 调用一个函数(例如 set_information()),该函数在每个请求上设置上下文或执行检查,并且您需要其他 Supabase 产品具有类似的行为,则必须在您的行级别安全 (RLS) 策略中直接调用该函数。
示例
如果您有一个调用 set_information() 的 db_pre_request 函数,该函数返回 true 以设置上下文或执行检查,并且您有一个如下的 RLS 策略
1create policy "Individuals can view their own todos."2on todos for select3using ( (select auth.uid()) = user_id );要实现其他 Supabase 产品的相同行为,您需要在 RLS 策略中直接调用该函数
1create policy "Individuals can view their own todos."2on todos for select3using ( set_information() AND (select auth.uid()) = user_id );这确保了该函数在评估所有产品的 RLS 策略时都会被调用,而不仅仅是 Data API 请求。
性能考虑
请注意,在 RLS 策略中直接调用函数可能会影响数据库性能,因为该函数会在检查策略时为每一行进行评估。如果性能成为问题,请考虑优化您的函数或使用缓存策略。
将 '123.123.123.123' 替换为您的实际 IP 地址。
禁用 explain#
要在使用后禁用 explain() 方法,请执行以下 SQL 命令
1-- disable explain2alter role authenticator3set pgrst.db_plan_enabled to 'false';45-- if you used the above pre-request6alter role authenticator7set pgrst.db_pre_request to '';89-- reload the config10notify pgrst, 'reload config';