Supabase实战指南:从云服务到本地部署的PostgreSQL全栈后端

做全栈项目时,最让我上头的后端服务其实是Supabase:它把PostgreSQL、Auth、Realtime、存储和Edge Functions打包成一个平台,云服务和本地部署都能跑通,专门用来做原型和中小型项目几乎不用自己写后端。尤其是现在大家都在用AI编程助手生成SQL和接口代码,Supabase作为底层是PostgreSQL的开源方案,反而比封闭式BaaS更好适配AI编程,这也是我今天想系统聊一聊的原因。

这篇文章会把Supabase的两条路线都过一遍:云服务怎么连、怎么建表、怎么接认证和存储;本地部署怎么用CLI拉起整套环境。中间会穿插PostgreSQL高级特性的实战,比如RLS行级安全、触发器、全文检索、pgvector这些,最后一节再讲怎么让AI助手生成更靠谱的Supabase代码。

如果你是独立开发者、小团队,或者正在做AI应用原型,应该能从里面找到可以直接抄作业的部分;就算你只是想把数据库技能再往上提一档,看完也能明白为什么一堆人把“业务逻辑下沉到数据库”当成一种开发方式。

1. Supabase到底解决了什么问题

1.1 先从定位说起:开源版Firebase,但本质是PostgreSQL

说起后端基建,大部分全栈项目在初期都逃不开这几件事:建数据库、做用户认证、传文件、实时推送、写接口。传统做法是自己搭服务,一个人干运维的活;后来Firebase把这些东西都打包了,确实省事,但它的底层是文档型数据库,和前端打交道很爽,一旦遇到复杂查询、报表统计、事务一致性,就又开始劝退了。

Supabase当年出来的时候打的旗号就是“开源版Firebase”,但它真正的内核是标准PostgreSQL。这意味着你拿到的不是一套私有API,而是一个你能直接连接、直接执行SQL的数据库,REST接口只是PostgREST自动映射出来的一个外壳。你能用psql连进去,能用任何支持PostgreSQL的工具做迁移、做备份、做监控,哪一天不想用Supabase了,数据也不会被锁死。

我用一个类比来解释:Firebase像品牌精装房,拎包入住但户型不能改;Supabase像是你买到了标准户型但可以砸墙改造的房子,关键结构都是行业通用的,装修方案随时可以换。

那它适合谁?独立开发者、小团队、AI应用原型、内部工具、Hackathon项目,都很适合。它的缺点也很明显:高度依赖PostgreSQL生态,如果团队里没人懂SQL,光靠Dashboard点点点,迟早会被复杂的业务卡住;另外大并发和强治理体系下,自托管也意味着所有运维责任自己扛。

1.2 为什么说PostgreSQL是它的灵魂

把Supabase的所有功能拆开看,会发现它们全挂在同一个PostgreSQL上。Auth不是独立的用户系统,它有一组auth schema的表;Storage的权限规则本质是storage.objects表上的RLS策略;Realtime监听的是PostgreSQL的变更流;Edge Functions跑在Deno上,但日常读写还是走PostgREST。换句话说,你学会SQL,就等于掌握了这个平台的核心控制权。

这也是我推荐大家学Supabase时一定要补PostgreSQL高级特性的原因。很多人把它当做一个“表格托管工具”,只会在Dashboard里点点“Add Row”,遇到权限、并发、全文搜索、向量检索这些事情就抓瞎了,但其实这些功能PostgreSQL本身就支持。

举几个具体例子:

  • RLS行级安全,可以做到每个用户只能查自己那几行数据;
  • JSONB字段,可以支撑灵活的业务扩展而不需要频繁改表;
  • pg_trgm和全文检索,中小项目可以直接在数据库里做搜索;
  • pgvector,AI应用里的向量相似度检索可以直接在SQL里ORDER BY。

这些东西对AI编程适配也特别重要。使用AI编程助手时,数据库能力越标准、越通用,AI生成的代码就越容易落地。Supabase因为完全基于PostgreSQL,AI模型对PostgreSQL语法的理解已经很成熟,生成出来的SQL、迁移脚本、Triggers、Policies,基本都能直接执行。换成某个封闭BaaS的私有API,AI生成的代码常常是看着像、跑不通。

2. 云服务快速上手:从建项目到拉通全栈

2.1 创建项目与连接信息,别搞混几组Key

云服务是Supabase官方托管平台,省去运维成本。注册登录后创建组织、创建项目,选一个离业务用户近的Region,然后设置数据库密码,十几分钟就能拉起一个新项目。项目创建完,你会拿到一组信息,很多人在这里就栽了跟头,因为同时出现的Key和连接串太多,不知道谁该用在哪。

需要记住四样东西:

  • Project URL,也叫API URL,格式类似https://xxxx.supabase.co,是客户端请求REST接口的域名;
  • anon key,公开的匿名密钥,可以暴露在前端,配合RLS使用;
  • service_role key,服务端密钥,会绕过RLS,有几乎全部权限,绝对不能出现在前端代码里;
  • Database connection string,PostgreSQL原生连接串,用数据库工具、后端服务、脚本连接时用。

我见过太多初学者把service_role key直接放在前端代码里,等于把数据库管理员权限交给浏览器,这说明没理解RLS和service_role的分工。anon key只是一个“匿名标识”,真正决定数据能不能被读取的是数据库端的安全策略。只要没开RLS,任何人拿anon key都能读全表,这时候就算你把service_role key藏得再好,数据一样是裸奔的。

连接串的格式类似下面这样:

postgresql://postgres:your_password@db.example.supabase.co:5432/postgres

要注意:如果密码里包含@、#、?这类特殊字符,必须做URL编码,否则客户端会解析错。另外云服务上还有“直连”和“连接池”两种连接方式,端口可能不同,项目面板里会标注,用错了会出现能连上但SQL频繁超时之类的问题。

2.2 用supabase-js写第一个读写接口

云服务项目建好后,最快感受这套体系的方式是写一个最小客户端。先安装官方JavaScript客户端:

npm install @supabase/supabase-js

然后初始化:

import { createClient } from '@supabase/supabase-js' const supabase = createClient( 'https://your-project.supabase.co', 'your-anon-key' )

读一张表,加上关联查询:

const { data, error } = await supabase .from('posts') .select('id, title, author:users(id, name), tags(name)') .order('created_at', { ascending: false }) .range(0, 9)

这段代码最后会被PostgREST翻译成SQL,支持过滤、排序、分页、关联子表,语法非常接近SQL,所以只要你对PostgreSQL的JOIN和WHERE有感觉,写起来就很顺手。比如过滤只要把.eq('status', 'published')加上就行。

踩过的坑是:不少人刚用的时候以为客户端拿到的数据都是实时的,其实普通查询就是普通HTTP请求,Realtime需要另开订阅功能。另外PostgREST对单次返回的行数和响应体积有默认限制,不要想着一条查询把整个表拉下来,超过限制会报错,正确做法是分批拉或者加条件缩小范围。

2.3 Auth、Storage、Realtime、Edge Functions一把梭

Auth模块支持邮箱密码、短信、OAuth,登录后返回JWT,Supabase会自动把用户ID放在认证上下文中,数据库里通过auth.uid()就能拿到当前登录用户ID,这是RLS策略里最常用的函数。

Storage模块负责对象存储,可以建public桶和private桶,文件权限本质还是通过SQL策略来控制。公开桶适合放头像、封面图,私有桶适合放用户隐私文件,访问时生成短期签名URL。

Realtime模块可以监听表的INSERT、UPDATE、DELETE事件,适合聊天室、通知、协同编辑这类需求。Edge Functions跑在Deno上,部署冷启动略慢,但不需要维护一套Node服务,适合做webhook和轻量代理层。

我的实际体验是:云服务适合快速验证业务逻辑,尤其是SQL Editor和Studio的可视化体验很顺手;但如果项目要长期迭代,必须把迁移脚本、种子数据、环境配置这些工程化能力补齐,这就自然进入下一节内容:本地部署。

3. 本地部署:从零跑通自托管环境

3.1 为什么值得在本机弄一套

很多人的第一反应是“有云服务为什么还要本地部署?”真到项目里就会发现原因很实际:第一,离线开发不消耗云资源额度,不会在调试时把免费的容量耗尽;第二,本机可以随时db reset,把数据库恢复到干净状态,配合种子数据,反复测试迁移脚本毫无压力;第三,本地环境逼着你用命令行管理迁移,而不是总去点Dashboard,这对生产环境的自动化部署是正向帮助。

本地部署还有一个隐藏价值:作为AI编程适配的“试验沙盒”。用AI助手生成一段SQL或一个RLS策略,先在本地数据库执行验证,跑通了再推给云环境,效率高很多,也不会把生产数据搞乱。

前提条件很简单:装好Docker,并保证至少有4GB左右可用内存,否则一下拉起十来个容器会比较吃力。Windows上建议用WSL2里的Docker Desktop,macOS用新版Docker Desktop就行。

3.2 用Supabase CLI一键拉起

官方推荐的本地开发方式是Supabase CLI。安装好后初始化项目:

supabase init

这会生成一个supabase目录,里面是配置和迁移文件。接着直接启动:

supabase start

第一次会拉取镜像,在一两分钟后,终端会打印出本地服务地址。典型输出是这样的:

API URL: http://localhost:54321 DB URL: postgresql://postgres:postgres@localhost:54322/postgres Studio URL: http://localhost:54323 anon key: ... service_role key: ...

这些地址分别对应API服务、数据库、管理后台Studio。浏览器打开Studio URL,就能看到和云服务几乎一样的界面,可以在里面建表、写SQL、配认证、传文件。

本地迁移脚本放在supabase/migrations里,推荐用命令创建:

supabase migration new create_profiles

然后在生成的SQL文件里写表结构,写完执行:

supabase db push

这套语法和云服务基本通用,本地写好的迁移可以直接推到远程项目。还有几个常用命令值得形成肌肉记忆:supabase stop停止容器但保留数据;supabase db reset重置数据库到最新迁移并跑种子数据;supabase gen types typescript --project-id your_project_id导出TypeScript类型。

我个人的工作流是:本地写完迁移和种子数据,用db reset反复重置验证,然后推到开发环境的Supabase项目,最后再在生产项目执行同样的迁移。这样整个流程是可控的,不会出现“我在Demo环境手点了几行数据,结果生产环境没有”的尴尬。

3.3 自托管生产环境的架构与配置

本地CLI更适合开发,如果真要自托管上线,得了解生产级部署的架构。官方开源的docker-compose包含多个组件,核心链路可以概括成:客户端请求先经过Kong网关,Kong根据路径分发到PostgREST、GoTrue、Storage API、Realtime等后端服务,这些服务统一读写同一个PostgreSQL。

组件职责大致如下:

组件职责
PostgreSQL数据存储,也保存Auth和Storage的元数据
PostgREST把数据库表映射成REST API
GoTrue认证管理,签发和校验JWT
KongAPI网关,统一入口和路由
Studio管理后台界面
Realtime数据库变更推送和WebSocket
Storage API对象存储的API层
Edge RuntimeDeno边缘函数运行环境

自托管生产环境的资源消耗明显比本地开发高,我建议起步配置至少4核8G,磁盘用SSD,数据库和备份要单独规划。云服务帮你做了自动备份、邮件、短信、日志和监控,自托管后这些都要自己搭或者接入第三方,工作量不小。所以我的建议是:如果团队没有专职运维,优先用云服务;本地部署更多作为开发和测试环境,而不是为了省那点托管费把自己拖进运维泥潭。

4. 把PostgreSQL高级特性用起来:表设计、触发器、RLS与向量检索

4.1 别只会用text和serial:常用类型与约束

在Supabase里建表,最无奈的是看到有人把一切字段都设为text,连ID都是自增serial。PostgreSQL的类型系统非常强大,用对了能让数据更干净、查询更快。

举个例子,一个商品表可以这样设计:

create table public.products ( id uuid primary key default gen_random_uuid(), sku text not null unique, name text not null, price numeric(12,2) not null check (price >= 0), tags text[] not null default '{}', metadata jsonb not null default '{}', created_at timestamptz not null default now(), updated_at timestamptz not null default now() );

这里面有几个值得说的点:

  • id uuid primary key:用UUID而不是自增ID,避免暴露业务数据量,也方便客户端生成ID;
  • price numeric(12,2):钱不要用float,浮点误差会在结算时变成事故;
  • check (price >= 0):数据库层的约束比应用层校验更可靠,任何入口写入都会被拦截;
  • tags text[]:数组类型在需要打标签的场景很好用;
  • metadata jsonb:灵活扩展字段,适合存那些变化频繁的非关键属性。

JSONB虽然灵活,但不要滥用。如果某个字段要频繁参与WHERE过滤或排序,应该提取成独立列并加索引,JSONB里的数据做条件查询虽然能用GIN索引,但比常规列麻烦很多。

4.2 函数与触发器:自动维护updated_at与审计日志

很多人在应用层里手动维护updated_at,但代码一多总有遗漏。PostgreSQL的触发器可以在数据库库层面保证这个字段被自动维护,任何入口修改都会触发。

一个通用写法是创建一个PKG函数和触发器:

create or replace function public.set_updated_at() returns trigger language plpgsql as $$ begin new.updated_at := now(); return new; end; $$; create trigger trg_products_updated_at before update on public.products for each row execute function public.set_updated_at();

这样应用层再也不用管updated_at,只要执行UPDATE,这个字段就会自动刷新。

触发器另一个常见用途是审计日志。比如记录谁在什么时候删了订单:

create table public.order_audit ( id bigint generated always as identity primary key, order_id bigint not null, operation text not null, old_status text, new_status text, changed_by uuid, changed_at timestamptz not null default now() ); create or replace function public.log_order_change() returns trigger language plpgsql as $$ begin insert into public.order_audit (order_id, operation, old_status, new_status, changed_by) values (new.id, tg_op, old.status, new.status, auth.uid()); return new; end; $$; create trigger trg_order_audit after update on public.orders for each row when (old.status is distinct from new.status) execute function public.log_order_change();

这里用到了tg_op表示当前操作类型,用auth.uid()记录操作人。这种“数据库自治”的思路,让审计逻辑不会因为某个应用忘记调用而缺失。

注意事项有两个:一是触发器函数抛错会让整个事务失败,所以要先在小数据集上验证;二是高频率批量操作时,逐行触发器会带来额外开销,对于超大日志表要评估后再决定是否使用。

4.3 RLS行级安全:后端权限的核心防线

RLS是Supabase权限体系里最核心的东西。在传统开发里,后端接口负责过滤数据;但在Supabase这种“客户端直连API”的架构下,RLS成了真正的一道防线,它在数据库层面对每一行数据执行安全策略。

先看一个标准示例。假设有个帖子表public.posts,里面有个字段user_id表示作者:

alter table public.posts enable row level security; create policy "用户可以读自己的帖子" on public.posts for select using (auth.uid() = user_id); create policy "用户只能新增自己的帖子" on public.posts for insert with check (auth.uid() = user_id); create policy "用户可以更新自己的帖子" on public.posts for update using (auth.uid() = user_id) with check (auth.uid() = user_id);

这里的关键是区分USING和WITH CHECK:

  • USING判断已有行是否可以被操作,比如SELECT能不能看到某行,UPDATE和DELETE能不能匹配到某行;
  • WITH CHECK约束新写入的数据是否符合条件,比如INSERT时user_id是否等于当前用户,UPDATE之后user_id是否仍然等于当前用户。

RLS不开的话,任何拿到anon key的人都能查全表,这是Supabase新手最容易犯的严重错误。判断一张表有没有“裸奔”,最简单的方式是在SQL Editor里直接执行:

select relname, relrowsecurity from pg_class where relname = 'posts';

如果relrowsecurity是false,说明这张表对匿名用户完全敞开,必须赶紧enable row level security。

另外要记住:service_role key会绕过RLS,这是设计如此。所以常规业务的前端请求都应该用anon key加上用户登录后的JWT,绝不能让service_role key出现在客户端。

4.4 视图、物化视图与全文检索的实战姿势

视图能极大简化常规查询。PostgREST也支持把视图暴露成API,但需要注意不是所有视图都可以自动更新,复杂视图通常只能读。所以我更倾向于把视图当成“只读的报表层”,给前端提供整理好的数据形状。

如果查询很重,比如要对订单表按天聚合统计,直接在视图上每次都重算会很慢,这时候用物化视图:

create materialized view public.daily_order_stats as select date_trunc('day', created_at)::date as day, count(*) as order_count, sum(amount) as total_amount from public.orders group by 1; create unique index daily_order_stats_day_idx on public.daily_order_stats(day); refresh materialized view concurrently public.daily_order_stats;

生产环境里建议用定时任务或触发器来刷新物化视图,不要每次查询都手动刷新。

全文搜索也是PostgreSQL的招牌特性。Supabase里做文章搜索可以这样:

alter table public.posts add column search_tsv tsvector generated always as ( to_tsvector('simple', coalesce(title, '') || ' ' || coalesce(content, '')) ) stored; create index posts_search_tsv_idx on public.posts using gin (search_tsv); select id, title from public.posts where search_tsv @@ websearch_to_tsquery('simple', 'supabase postgres');

用生成列维护tsvector,能避免应用层手工维护造成的数据不一致。GIN索引支撑中文、英文分词后的检索,中小项目完全够用,等到数据量到了几百万级、搜索逻辑复杂了,再考虑独立的搜索服务也不迟。

4.5 pgvector与AI应用结合:向量检索直接进数据库

现在AI应用几乎绕不开向量检索。以前要单独部署向量数据库,现在PostgreSQL的pgvector扩展直接在Supabase里就能用,省掉一套基础设施,也让向量可以和其他业务数据一起做JOIN和过滤。

先启用扩展并建表:

create extension if not exists vector; create table public.embeddings ( id uuid primary key default gen_random_uuid(), content text not null, embedding vector(1536) not null ); create index embeddings_hnsw_idx on public.embeddings using hnsw (embedding vector_cosine_ops);

检索时用向量距离排序,拿语义最相近的前10条:

select id, content, 1 - (embedding <=> :query_vector) as similarity from public.embeddings order by embedding <=> :query_vector limit 10;

<=>是余弦距离运算符,返回值越小表示越相似。索引上我用的是hnsw,它精度高、查询快,代价是内存占用偏大;如果数据量不大或者离线生成索引可以接受,也可以用ivfflat,它召回率略低但建索引速度快。具体选哪个,最好用真实数据做一轮对比。

要注意向量维度必须和嵌入模型输出的维度一致,比如某些文本模型输出1536维,建表时就写vector(1536)。向量检索的索引参数也需要调优,比如hnsw的m和ef_construction,默认值适合大多数场景,但特殊数据分布下调整后效果会差很多。

这一块对AI编程适配的意义在于:很多AI应用后端都要同时处理普通业务数据、向量数据和权限控制,pgvector把这个复杂度收进了SQL里,AI助手也能很方便地生成对应查询代码。

5. AI编程适配:让AI助手更懂你的Supabase

5.1 先给AI一份“数据库上下文”

AI编程助手生成Supabase代码时,经常翻车的根源不是AI能力不够,而是它缺少项目的上下文。它默认只知道通用SQL,不知道你这个表开了RLS没有、auth.uid()怎么用、装了哪些扩展,所以生成的东西看起来合理,跑起来全是坑。

我在实际操作中会先给AI一段结构化的“数据库上下文”,模板大概是:

项目:社区内容系统 数据库:Supabase / PostgreSQL 15 表结构: - public.users(id uuid primary key, username text unique, avatar_url text) - public.posts(id uuid primary key, user_id uuid references public.users(id), title text, content text, created_at timestamptz) 权限要求: - 普通用户只能读和改自己的帖子 - 管理员可以读所有帖子 - 匿名用户不可写 扩展:pgvector, pg_trgm 请为以下需求生成SQL或supabase-js代码: ...

这样AI生成的RLS策略、查询语句、TypeScript代码都会准确很多。另外一个非常推荐的做法是使用supabase gen types生成TypeScript类型文件,然后直接把类型文件喂给AI。AI看到确切的类型定义后,生成的代码基本不会出现“user_id不存在”这类低级错误。

我现在的习惯是:一个模块一个模块让AI生成,而不是让它一次生成整个系统。比如先让它生成“帖子表+RLS策略”,本地跑通后再让它生成“查询帖子的API代码”,这样每一段都能快速验证,出了问题也能精准定位。

5.2 AI生成SQL的Review清单

AI生成的SQL,用之前一定要基于下面这个清单做检查,能过滤掉90%的线上事故:

检查项常见问题正确做法
RLS表没enable row level security每张业务表都显式开启RLS
外键外键列没有索引,删父表时锁表为外键列创建索引
主键用serial自增优先用uuid或generated always as identity
更新手动更新updated_at用触发器自动维护
查询select *全字段拉取只select需要的列
批量写循环单条insert用insert多条或事务包装
安全拼字符串拼接产生SQL注入使用参数化查询
权限应用层过滤数据用RLS在数据库层过滤

还有一个高频问题:AI生成SQL时喜欢把一切都放在publicschema里,这没问题;但有时它会生成create extension却不标注schema,在Supabase里执行会有权限报错。建议让AI显式使用Supabase推荐的方式,例如创建扩展时写成create extension if not exists pg_trgm schema extensions;,或者干脆询问官方文档的写法。

Review完之后还要做一轮行为测试。我经常在本地起一个临时表,让AI生成脚本执行,然后模拟不同身份测试RLS是否生效。这个流程成本很低,却能在代码推到生产之前堵住大多数权限漏洞。

5.3 实战:让AI生成一条完整的RLS策略

我给大家还原一个实战场景。我需要为订单表生成RLS策略,需求是:

请为Supabase/PostgreSQL生成RLS策略: - 表 public.orders,字段有 id、user_id、state、amount、created_at - 普通用户(authenticated)只能 select 自己的订单 - insert 时 user_id 必须等于 auth.uid() - 用户不能直接修改订单的 state 字段 请输出完整SQL。

AI第一版通常会给这样的代码:

alter table public.orders enable row level security; create policy "用户可查自己的订单" on public.orders for select using (auth.uid() = user_id); create policy "用户可插入自己的订单" on public.orders for insert with check (auth.uid() = user_id);

这一段基本是对的,但需求里“用户不能直接修改订单的 state 字段”还没落地。继续追问后,AI补出了更新策略:

create policy "用户可更新自己的订单但不可改state" on public.orders for update using (auth.uid() = user_id) with check ( auth.uid() = user_id and state = old.state );

最终我还会加一条DELETE策略和必要的索引。整个过程验证方式是:先在本地用两个测试用户分别登录,A用户只能看到A的订单;再尝试用A的token更新B的订单,应该被拒绝;最后尝试把state改成新值,应该也失败。

这种验证完的策略才算真正能上线。AI给的是初稿,我们做的是把它放进数据库业务边界里打磨。

6. 高频问题排查实录:快速定位Supabase与Postgres的坑

6.1 连接失败与IPv6、连接池端口

云数据库连接串的域名有时候会解析到IPv6地址,但本地网络环境不太支持IPv6,这时候psql或数据库客户端会一直卡在连接超时。排查方式很简单:先看报错是“connection refused”还是“timeout”,前者多半是端口或权限问题,后者要先怀疑网络协议问题。处理办法之一是在客户端里强制使用IPv4,或者在连接串里显式指定连接参数。

另一个高频问题是端口混淆。Supabase项目面板会给出“Direct connection”和“Connection pooler”两类连接信息,端口可能不同。直连适合运维脚本、批量任务,但客户端应用建议走连接池,否则连接数一多就会出现“Too many clients”的错误。

我自己的排查顺序是:先用psql在服务器或本地命令行测试连接串,确认能连上,再回头看ORM或客户端配置,这样能把“数据库问题”和“应用配置问题”快速分离。

6.2 本地部署时的Docker与内存问题

supabase start启动到一半容器反复重启,最常见的锅是Docker可用内存不足。Supabase本地环境要跑PostgreSQL、Kong、Studio等十几个容器,内存建议给到4GB以上。Docker Desktop的设置里调高内存后,执行supabase stop再supabase start,问题通常就能解决。

还有一类问题是端口冲突,尤其是本机已经装了PostgreSQL,5432端口被占,supabase start会报端口绑定失败。解决办法是改CLI配置里的映射端口,或者先停掉本机数据库服务。

本地环境偶发报mbind: Operation not permitted,这是容器运行时权限限制造成的,大多数情况下不影响使用,也不需要处理。如果实在介意,可以在Docker Desktop的Resource设置里调整相关选项。

重点提醒:supabase stop不会删数据,数据还在Docker卷里;只有supabase db reset才会把数据库重置到迁移和种子数据状态。所以调试阶段可以大胆db reset,但不要期望stop能帮你“还原现场”。

6.3 Postgres与PostgREST的排查思路

API请求返回空数组,但你在SQL Editor里查明明有数据,这是Supabase里非常经典的“看起来像Bug其实不是Bug”的问题。第一步先确认这张表有没有开RLS,开了的话当前JWT对应的用户是否有对应策略;第二步检查你是不是用anon key在查,而表的SELECT策略只允许authenticated角色访问。

SQL Editor能执行、但API请求报权限错误,大概率也是RLS策略没写对,或者你在API请求里用了某个字段,但该字段不在对应策略允许范围内。

慢查询的定位可以从统计视图入手:

select query, calls, total_exec_time from pg_stat_statements order by total_exec_time desc limit 10;

看到某条SQL特别慢后,单独用explain analyse跑一遍执行计划,判断是缺索引还是逻辑上可以重构。索引问题在PostgreSQL里最常见的就是:WHERE字段上有函数或类型转换,导致普通索引失效;解决办法是建表达式索引或者统一字段类型。

最后分享一个经验:Supabase的问题,90%都出在“对PostgreSQL的理解不够深”。画图排坑、来回切换客户端,不如先想办法在SQL Editor里把SQL写对。数据库本身是可靠的,它只会严格执行你定义的规则;你定义得越清晰,后面的应用层就越省事。

最后说点我自己的体会。用Supabase这一年多,我最大的变化是慢慢把权限判断从应用层搬到了数据库层,这是一种很舒服的开发方式——前端不用为了一个列表页写三套判断逻辑,AI编程时也会因为上下文清晰而给出更靠谱的SQL和API代码。如果你正准备上手,我建议先跑通本地CLI、做一版带RLS的表结构,再考虑上云服务;遇到问题先去SQL Editor验证SQL本身,再回头看API调用,你会发现大部分问题其实出在对PostgreSQL的熟悉程度上。希望这篇能帮你少踩几个坑。

相关新闻

用Python深度学习实现墙体裂缝有无识别:完整项目实战指南

用Python深度学习实现墙体裂缝有无识别:完整项目实战指南

最近有好几个准备做毕业设计的同学来问我同一个题目&#xff1a;用Python和深度学习做墙体裂缝的有无识别。这个题目看着简单&#xff0c;实际上从数据准备到模型训练再到答辩演示&#xff0c;每一步都有讲究。我当初做这个题目的时候&#xff0c;走了一条弯路——一上来就找目…

2026/10/20 14:55:49 阅读更多 →
POI-TL合并多个Word文档:两条路线与5个常见坑的完整解法

POI-TL合并多个Word文档:两条路线与5个常见坑的完整解法

简介&#xff1a;面向Java后端开发与办公自动化实施人员&#xff0c;这份资源系统讲解如何借助POI-TL技术实现多个Word文档的快速合并。POI-TL是Apache POI的扩展&#xff0c;专门用于处理.docx格式&#xff0c;提供了模板化编程接口&#xff0c;支持占位符替换以及段落、表格的…

2026/10/20 14:55:49 阅读更多 →
链表刷题进阶:虚拟头节点与反转链表的核心技巧解析

链表刷题进阶:虚拟头节点与反转链表的核心技巧解析

连着刷了两天数组和哈希表&#xff0c;第三天题目下来一看——203.移除链表元素、707.设计链表、206.反转链表。说实话&#xff0c;看到“链表”两个字我是有点慌的&#xff0c;数组好歹能用下标走天下&#xff0c;链表这玩意儿的指针和节点关系&#xff0c;在脑子里转着转着就…

2026/10/20 14:55:49 阅读更多 →

最新新闻

TensorFlow鞋类识别实战:Fashion MNIST图像分类全流程

TensorFlow鞋类识别实战:Fashion MNIST图像分类全流程

前段时间重新整理之前的深度学习实验笔记&#xff0c;翻到鞋类识别&#xff08;Fashion MNIST&#xff09;这个项目时&#xff0c;觉得特别值得拿出来单独写一篇。原因很简单&#xff1a;很多人入门深度学习时&#xff0c;都会被建议先跑通手写数字识别&#xff08;MNIST&#…

2026/10/20 20:57:37 阅读更多 →
用AI辅助Kamailio路由排错:一场人机讨论实录与故障切换实践

用AI辅助Kamailio路由排错:一场人机讨论实录与故障切换实践

最近接手一套老的SIP通信平台&#xff0c;核心信令是Kamailio撑着。业务要新增一个较复杂的路由策略&#xff1a;同一个主叫号码&#xff0c;在不同时间段、针对不同被叫前缀&#xff0c;要分别走不同的网关&#xff1b;而其中一路网关做故障切换时&#xff0c;还要保证已经建立…

2026/10/20 20:57:37 阅读更多 →
LibVLC轻量级视频播放模块:嵌入C/C++工程的硬件解码方案

LibVLC轻量级视频播放模块:嵌入C/C++工程的硬件解码方案

简介&#xff1a;本资源是一份基于C/C与VLC开源库开发Windows视频播放器的完整工程实践包&#xff0c;面向具备基础C编程能力、希望掌握多媒体开发技能的中级开发者及高校课程设计学习者。资源聚焦于在Visual Studio 2022环境下集成libvlc实现视频加载、播放控制、窗口渲染等核…

2026/10/20 20:57:37 阅读更多 →
AI Agent创业团队如何配置一支高效的Harness Engineering团队

AI Agent创业团队如何配置一支高效的Harness Engineering团队

1. 为什么需要一支专门的Harness Engineering团队先从一个很现实的场景说起&#xff1a;你所在的创业团队花三个月做出了一个基于大模型的Agent产品Demo&#xff0c;演示给投资人看时效果炸裂&#xff0c;但真正进入客户试用阶段&#xff0c;问题接踵而来——模型给出正确意图却…

2026/10/20 20:57:37 阅读更多 →
视觉语言模型与RGB-D感知融合:三条进化主线与工程实践

视觉语言模型与RGB-D感知融合:三条进化主线与工程实践

1. 从 Transformer 到多模态感知的演进逻辑视觉语言模型和 RGB-D 感知这两个方向&#xff0c;过去几年基本是各走各的路。做 VLM 的人盯着图文对齐、指令跟随、视觉问答这些任务&#xff0c;做 RGB-D 的人则埋头于点云配准、深度补全、SLAM 建图。但最近一年&#xff0c;这两条…

2026/10/20 20:57:37 阅读更多 →
VTI介质地震波数值模拟:MATLAB实现与各向异性正演避坑指南

VTI介质地震波数值模拟:MATLAB实现与各向异性正演避坑指南

简介&#xff1a;这份资源面向地震勘探与地球物理方向的学习者和研究者&#xff0c;提供一套基于Matlab的VTI介质地震波场数值模拟程序&#xff0c;用于分析各向异性介质中地震波的传播规律。VTI介质在垂直与平行层理方向上纵波速度存在差异&#xff0c;是实际地壳中常见的各向…

2026/10/20 20:56:32 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →