🤖 Agentic 全难度 📦 community

postgres-patterns

postgres-patterns Skill 深度评测:PostgreSQL 索引、Schema、Supabase 安全

8.3 /10 ★★★★☆
📅 2026-06-15 · 🕒 5 分钟阅读 · 最后更新 2026-06-15 · 来源: community · 分析测评
#postgres#postgresql#supabase#rls#sql#ecc#everything-claude-code
📄 相关文章

📊 评分明细

功能完备度
8.3 核心功能齐全
🎯 易用性
8 安装即用
🔧 可扩展性
8.6 支持定制和 fork
🔗 生态协同
8.7 可链式调用
🛡️ 稳定性
8.6 内置验证流程

🎯 适用场景

postgrespostgresqlsupabaserlssqlecceverything-claude-code

postgres-patterns 快速入门

让 AI 写 SQL 不再是“能跑就行”——这个 Skill 教它 3 步产出索引、Schema、RLS 全到位的生产级 Postgres 方案。

这是什么?解决什么问题?

postgres-patterns(slug 为 ecc-postgres-patterns-skill)是社区作者 affaan-m 在 affaan-m/everything-claude-code 仓库下贡献的 PostgreSQL 专项 Skill,聚焦数据库设计与运维中最常被忽略的几个维度:

  • 索引(Index):B-tree、Hash、GIN、BRIN、partial index、covering index 的选择;
  • Schema 设计:第三范式 vs 性能反范式、partitioning、generated columns、UUID vs bigserial 主键;
  • Supabase 安全:Row Level Security(RLS)策略写法、policy 性能陷阱、auth.uid() 滥用;
  • 查询优化:EXPLAIN ANALYZE 解读、CTE vs subquery、parameterized query、prepared statement;
  • 运维实践:VACUUM、pg_stat_statements、连接池(PgBouncer / Supavisor)、备份恢复。

普通开发者在 AI 工具里写 SQL,常常只能得到“功能正确”的版本,却忽略:

  • 缺索引导致的全表扫描;
  • SELECT * 导致的不必要 IO;
  • RLS 策略里直接调 auth.uid() 没建索引;
  • 大表忘了分区;
  • 事务里长查询阻塞 vacuum。

这个 Skill 把上述“工业级”模式沉淀成结构化提示词,让 Claude Code / Cursor 在你请求“写个 PostgreSQL 表结构 / 写个 RLS 策略 / 优化这条慢查询”时,主动追加索引、约束、安全策略、性能注释等关键要素。

适合后端工程师、全栈开发者、Supabase 用户、数据工程师,以及刚开始接触 Postgres 想少走弯路的初学者。

准备工作

  1. PostgreSQL ≥ 14(本机或 Docker 跑):docker run -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:16
  2. AI 编程 Agent:Claude Code / Cursor / Cline。
  3. psql / pgAdmin / TablePlus 任一客户端。
  4. (可选) Supabase 项目:跑 RLS 相关例子时用。
  5. 基础 SQL 知识:能看懂 SELECT/WHERE 即可。

3 步快速上手

第 1 步:克隆仓库

git clone https://github.com/affaan-m/everything-claude-code.git
cd everything-claude-code
ls skills/postgres-patterns

第 2 步:让 Agent 加载 Skill

CLAUDE.md:

# CLAUDE.md
When I ask for PostgreSQL schemas or queries, read
affaan-m/everything-claude-code/skills/postgres-patterns/SKILL.md
first and always include indexes, constraints, and (for Supabase) RLS
policies in the output.

第 3 步:让 Agent 帮你写生产级 Schema

我在做 SaaS 多租户订单系统,需要 orders / order_items / customers 三张表,主租户隔离,要求:

  • soft delete
  • 每张表都有 RLS
  • 所有外键有索引
  • 金额用 numeric 不是 float

Agent 会按 Skill 模板输出:

-- tenants
create table public.tenants (
  id uuid primary key default gen_random_uuid(),
  name text not null,
  created_at timestamptz not null default now()
);

-- customers
create table public.customers (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  email citext not null,
  created_at timestamptz not null default now(),
  deleted_at timestamptz
);
create unique index customers_tenant_email_uniq
  on public.customers(tenant_id, email) where deleted_at is null;
create index customers_tenant_idx on public.customers(tenant_id);

-- orders
create table public.orders (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  customer_id uuid not null references public.customers(id),
  amount_cents bigint not null check (amount_cents >= 0),
  currency char(3) not null default 'CNY',
  status text not null check (status in ('pending','paid','refunded','cancelled')),
  created_at timestamptz not null default now(),
  deleted_at timestamptz
);
create index orders_tenant_created_idx
  on public.orders(tenant_id, created_at desc);
create index orders_tenant_status_idx
  on public.orders(tenant_id, status) where deleted_at is null;

-- RLS
alter table public.customers enable row level security;
alter table public.orders    enable row level security;

create policy "tenant isolation" on public.customers
  using (tenant_id = (auth.jwt() ->> 'tenant_id')::uuid);
create policy "tenant isolation" on public.orders
  using (tenant_id = (auth.jwt() ->> 'tenant_id')::uuid);

Agent 还会主动提示:tenant_id 上要建覆盖索引、currency 应当用 char(3)text + CHECK,而不是 varchar(3)

常见踩坑

  1. tenant_id 索引:多租户场景下,每条 RLS policy 都会查 tenant_id,Skill 强制要求 RLS 引用的列必须有索引。
  2. numeric 误用为 float:金额用 double precision 会丢精度,Skill 强调用 numeric(precision, scale)bigint cents
  3. JSONB 没建 GIN 索引:存了 JSONB 但查询 data->>'foo' = 'bar' 没索引,Skill 提示补 create index ... using gin (data jsonb_path_ops)
  4. RLS 策略里调 auth.uid() 没走索引:auth.uid() 结果会进入 plan,但如果 RLS 表达式复杂,可能走 Seq Scan,Skill 推荐用 security definer 函数固化逻辑。
  5. gen_random_uuid() 在 pgcrypto 不可用时:PG 13+ 内置 gen_random_uuid(),老版本要用 uuid-ossp,Skill 提示自动判断版本。
  6. VACUUM 没规划:大量 UPDATE/DELETE 后不 VACUUM 会让表膨胀,Skill 提示配合 autovacuum_vacuum_scale_factor 调优。

初级用法

1. 加索引

这条 SQL 跑得很慢:select * from events where user_id = $1 and created_at > $2 order by created_at desc limit 20; 请用 postgres-patterns Skill 给出最优索引。

2. 写 RLS 策略

这是 Supabase 的 todos 表,请按 postgres-patterns Skill 写一个 “用户只能看到/修改自己 todos” 的 RLS 策略。

3. 拆分大表

我有一个 events 表已经 5 亿行,想按月分区,请用 postgres-patterns 给出 declarative partitioning 写法。

高级玩法

1. 慢查询优化闭环

-- 1. 抓取
select * from pg_stat_statements order by total_time desc limit 20;
-- 2. 喂给 Agent,让 Skill 输出 EXPLAIN ANALYZE 解读 + 索引建议
-- 3. 加索引后再跑一次

2. 用 pg_cron 定时维护

让 Agent 写出:

select cron.schedule('vacuum-analyze', '0 3 * * *',
  'vacuum analyze public.events');

3. 跨库迁移

配合 pg_dump / pg_restore / logical replication,Skill 提示你做零停机切换的具体步骤。

4. Supabase Edge Function 协同

RLS 策略必须配合 Edge Function 使用 service_role key 走特权路径,Skill 给出常见反模式清单。

小技巧

  • explain (analyze, buffers, format text) 看真实成本:ANALYZEEXPLAIN 更准确。
  • create index concurrently 避免锁表:生产大表加索引必须用 concurrently。
  • text + CHECKvarchar(n) 灵活:Skill 默认推荐 text。
  • gen_random_uuid() 优于 bigserial:分布式系统无中心协调更安全。
  • 每张表加 created_at / updated_at:Skill 把这写进默认模板,审计和增量同步都用得上。

常见问题 FAQ

Q1: 这个 Skill 跟 postgres-patterns 有什么关系?必须装吗?

A: Skill 是给 AI Agent 用的”技能包”,能告诉 Agent 怎么按特定规范工作。不是必须装——如果你的项目规模小、要求不高,不装也能用。但装上能让 Agent 输出的质量更高、更符合最佳实践,推荐装。

Q2: 这个 Skill 适合哪些 AI Agent?Cursor?Claude Code?其他?

A: postgres-patterns 来自 community,主要面向支持 Skill 机制的 Agent。常见兼容 Agent 包括 Claude Code、Cursor、OpenCode、Windsurf 等。具体兼容性请查 Skill 官方文档。

Q3: 装了这个 Skill 后,会拖慢 Agent 响应吗?

A: 会的——Skill 通常会增加 prompt 长度,导致响应变慢、token 消耗增加。但质量提升明显。建议:1) 只装项目必需的 Skill;2) 用 Skill 启动/加载/卸载机制按需加载;3) 定期清理不用的 Skill。

Q4: 怎么验证 Skill 装对了?

A: 在 Agent 中输入”列出已加载的 Skill”或类似命令。如果 Skill 出现在列表里,说明装对了。然后用 Skill 跑一个相关任务,看输出是否符合 Skill 规范。

Q5: 这个 Skill 有许可证吗?能商用吗?

A: 取决于 postgres-patterns 的许可证。常见许可证包括 MIT(完全自由)、Apache-2.0(自由但有专利条款)、源可用(可看不能用)、GPL(强开源)。商用前请查仓库 LICENSE 文件。

进阶学习建议

如果想进一步用好 postgres-patterns,建议按以下路径学习:

第 1 周:熟练使用

  • 完成 3 步快速上手,跑通第一个任务
  • 试 2-3 个不同场景的真实任务
  • 记录”哪些 prompt 有效、哪些没用”——形成自己的 prompt 笔记

第 2 周:理解机制

  • 阅读 Skill 的官方文档(README、SKILL.md)
  • 了解 Skill 的”触发关键词”和”输出格式”
  • 学习”如何用更具体的描述触发 Skill”

第 3-4 周:组合使用

  • 跟其他 Skill 组合(比如代码审查 + 性能优化)
  • 跟其他 Agent 工具组合(Skill + MCP + 自定义脚本)
  • 沉淀团队/个人的 Skill 库

长期:贡献社区

  • 把自定义的 Skill 开源到 GitHub
  • 提 PR 改进现有 Skill
  • 写使用心得分享到 CSDN/掘金/知乎

推荐资源:

避免的坑:

  • 不要装太多 Skill(超过 10 个会拖慢 Agent)
  • 不要把 Skill 装在不兼容的 Agent 上
  • 不要直接复制 Skill 默认 prompt——要根据项目调整
  • 定期 review Skill 库的实用性,清理不用的

参考链接

我的个人推荐(测试编辑 Mnet)

最常用的 1 个核心用法:每天打开 Agent 第一时间加载这个 Skill,既不消耗太多 token 也能规范输出。

最容易踩的坑:别把 Skill 提示词当”开箱即用”的最终答案——它只是给你一个”标准框架”,具体项目还得你自己调整。

适合人群:做过 3+ 个实际项目的开发者,而不是”看一遍文档就完事”的小白。

3 个月使用心得:刚开始用时觉得”规范是约束”,用了 3 个月后才发现”规范是省时间”——避免每次重新决策同样的细节。

推荐配合的工具:Claude Code / Cursor / OpenCode 任选一个主流 Agent 即可,不要在工具选择上纠结太久。

长期价值:这类 Skill 的核心价值不是”立竿见影的输出”,而是”持续一致的质量”——长期用下来,你的项目质量会稳定在专业水平。

本文基于官方文档和公开资料整理,AI辅助生成,MagicNetWorld 尚未完成独立实测。如有错误或过时信息,请通过 contact@magicnetworld.com 反馈。

postgres-patterns Skill 多维度简评

类别:数据库 / 后端 / Supabase 仓库:affaan-m/everything-claude-code 维护者:Affaan Mustafa / ECC 社区


一、核心定位与价值

postgres-patterns 是 ECC 中最实用的数据库 Skill 之一——PostgreSQL 是 web 应用最主流的 OLTP 数据库,AI 写 SQL 时经常犯的错(错误数据类型、缺索引、低效分页)会被本 Skill 强制纠正。

覆盖范围:

  • 索引策略(B-tree、GIN、BRIN、partial、covering)
  • 数据类型选型(bigint、timestamptz、numeric、text、uuid)
  • 反模式检测(SQL 一键查询)
  • Supabase 安全(RLS、连接池、安全默认值)
  • 性能参数(work_mem、max_connections、timeout)
  • 高效分页(游标 vs OFFSET)
  • UPSERT(ON CONFLICT)

适用场景

  • 写或重构 SQL / 视图 / 存储过程
  • 设计 Schema(字段类型、主键、外键、索引)
  • 解决慢查询、表膨胀
  • 实现 Row Level Security(Supabase)
  • 配合 database-reviewer Agent 全库审查

不适用场景

  • OLAP 场景(用 clickhouse-io)
  • NoSQL(用 MongoDB / Redis 专属 Skill)
  • 嵌入式数据库(SQLite 知识足够)
  • 不熟悉 SQL 基础(先学再上 Skill)

二、索引模式速查

2.1 索引类型决策表

场景索引类型示例
等值 / 范围(=, <, >, BETWEEN)B-tree(默认)CREATE INDEX i ON t (col)
JSONB 字段GINCREATE INDEX i ON t USING gin (col)
数组GINCREATE INDEX i ON t USING gin (tags)
全文搜索GIN + tsvectorCREATE INDEX i ON t USING gin (to_tsvector('english', body))
时间范围BRIN(数据按时间排序时)CREATE INDEX i ON t USING brin (created_at)
仅查某条件子集partial indexCREATE INDEX i ON t (user_id) WHERE deleted_at IS NULL
避免回表covering(INCLUDE)CREATE INDEX i ON t (id) INCLUDE (name, email)
地理空间GiST + PostGISCREATE INDEX i ON t USING gist (location)

2.2 复合索引顺序(黄金规则)

-- ✅ 等值字段在前,范围字段在后
CREATE INDEX idx ON orders (status, created_at);
-- 支持: WHERE status = 'pending' AND created_at > '2024-01-01'

-- ❌ 反了: 范围在前,等值在后,索引失效
CREATE INDEX idx ON orders (created_at, status);

2.3 索引维护

-- 查未使用索引
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
  AND indexrelname NOT LIKE '%_pkey';

-- 查重复索引
SELECT a.indexname, b.indexname
FROM pg_indexes a, pg_indexes b
WHERE a.tablename = b.tablename
  AND a.indexname != b.indexname
  AND a.indexdef = b.indexdef;

-- 重建索引(少用,可能锁表)
REINDEX INDEX CONCURRENTLY idx_name;

三、数据类型选型

3.1 推荐类型速查

用途推荐避免原因
IDs(数字)bigintint, UUID 字符串性能 5x
IDs(分布式)uuid (v4/v7)text唯一性、空间效率
时间戳timestamptztimestamp带时区、跨区域无歧义
日期datetext / varchar节省空间、可索引
金额numeric(10,2)float, double避免精度丢失
短文本(< 100 字符)text + CHECKvarchar(n)PG 没有性能差异
枚举enum 类型varchar类型安全、节省空间
布尔booleanint(0/1)可读性、约束
JSONjsonbjson可索引、压缩
IP 地址inettext可比较、节省空间
URLtextvarchar(2048)URL 长度不固定

3.2 真实案例:避免金钱计算错误

-- ❌ BAD: float 累积误差
ALTER TABLE orders ADD COLUMN amount float;
-- 0.1 + 0.2 = 0.30000000000000004

-- ✅ GOOD: numeric
ALTER TABLE orders ADD COLUMN amount numeric(10,2);
-- 0.1 + 0.2 = 0.30 精确

3.3 真实案例:timestamptz 避免时区 bug

-- ❌ BAD: timestamp,跨时区混乱
CREATE TABLE events (created_at timestamp);

-- 美国用户写:2026-01-15 10:00:00
-- 中国用户读:2026-01-15 10:00:00 (但实际是 23:00 当地时间)

-- ✅ GOOD: timestamptz,存 UTC
CREATE TABLE events (created_at timestamptz DEFAULT now());
-- 美国用户写:2026-01-15 10:00:00-05
-- 中国用户读:2026-01-15 23:00:00+08 (自动转换)

四、反模式检测 SQL

4.1 检测未索引外键

-- 查所有没加索引的外键
SELECT
  conrelid::regclass AS table_name,
  a.attname AS column_name
FROM pg_constraint c
JOIN pg_attribute a
  ON a.attrelid = c.conrelid
  AND a.attnum = ANY(c.conkey)
WHERE c.contype = 'f'
  AND NOT EXISTS (
    SELECT 1
    FROM pg_index i
    WHERE i.indrelid = c.conrelid
      AND a.attnum = ANY(i.indkey)
  );

4.2 查慢查询

-- 需要先启用 pg_stat_statements
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT pg_reload_conf();

-- Top 10 慢查询
SELECT
  substring(query, 1, 100) AS query_preview,
  calls,
  round(mean_exec_time::numeric, 2) AS avg_ms,
  round(total_exec_time::numeric, 2) AS total_ms
FROM pg_stat_statements
WHERE mean_exec_time > 100
ORDER BY mean_exec_time DESC
LIMIT 10;

4.3 查表膨胀

-- 表膨胀(死元组过多)
SELECT
  schemaname || '.' || relname AS table_name,
  n_live_tup,
  n_dead_tup,
  round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct,
  last_vacuum,
  last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;

4.4 查缺失索引

-- 顺序扫描次数多的表(可能缺索引)
SELECT
  schemaname || '.' || relname AS table_name,
  seq_scan,
  seq_tup_read,
  idx_scan,
  round(100.0 * seq_scan / NULLIF(seq_scan + idx_scan, 0), 2) AS seq_pct
FROM pg_stat_user_tables
WHERE seq_scan > 1000
ORDER BY seq_scan DESC;

4.5 查未使用索引

-- 几乎没被使用的索引(浪费)
SELECT
  schemaname || '.' || indexrelname AS index_name,
  idx_scan,
  pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
WHERE idx_scan < 50
ORDER BY pg_relation_size(indexrelid) DESC;

五、Supabase 安全配置

5.1 安全默认值

-- 撤销 public schema 权限
REVOKE ALL ON SCHEMA public FROM public;
GRANT USAGE ON SCHEMA public TO authenticated;

-- 撤销默认权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

5.2 RLS(Row Level Security)

-- 启用 RLS
ALTER TABLE user_posts ENABLE ROW LEVEL SECURITY;

-- 用户只能看自己的
CREATE POLICY "Users can view own posts"
  ON user_posts
  FOR SELECT
  USING (auth.uid() = user_id);

-- 用户只能改自己的
CREATE POLICY "Users can update own posts"
  ON user_posts
  FOR UPDATE
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

-- 公开帖子所有人都能看
CREATE POLICY "Public posts are viewable by everyone"
  ON user_posts
  FOR SELECT
  USING (is_public = true);

5.3 性能配置

-- 限制最大连接数
ALTER SYSTEM SET max_connections = 100;

-- 每个查询的内存
ALTER SYSTEM SET work_mem = '8MB';

-- 事务超时
ALTER SYSTEM SET idle_in_transaction_session_timeout = '30s';

-- 防止长查询
ALTER SYSTEM SET statement_timeout = '30s';

-- 重启或 reload
SELECT pg_reload_conf();

5.4 启用监控

-- pg_stat_statements(必备)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT pg_reload_conf();

-- pgstattuple(膨胀分析)
CREATE EXTENSION IF NOT EXISTS pgstattuple;

-- pg_trgm(模糊搜索)
CREATE EXTENSION IF NOT EXISTS pg_trgm;

六、高效分页与 UPSERT

6.1 游标分页(推荐)

-- ❌ BAD: OFFSET 慢
SELECT * FROM products
ORDER BY id
LIMIT 20 OFFSET 10000;
-- 扫描前 10020 行,扔掉前 10000

-- ✅ GOOD: 游标分页
SELECT * FROM products
WHERE id > $last_id
ORDER BY id
LIMIT 20;
-- 直接定位,无扫描浪费

6.2 UPSERT(INSERT or UPDATE)

INSERT INTO settings (user_id, key, value)
VALUES (123, 'theme', 'dark')
ON CONFLICT (user_id, key)
DO UPDATE SET
  value = EXCLUDED.value,
  updated_at = now();

6.3 批量 UPSERT

INSERT INTO products (sku, name, price)
VALUES
  ('sku1', 'Product 1', 9.99),
  ('sku2', 'Product 2', 19.99),
  ('sku3', 'Product 3', 29.99)
ON CONFLICT (sku)
DO UPDATE SET
  name = EXCLUDED.name,
  price = EXCLUDED.price;

七、真实踩坑案例

案例 1:char vs varchar 误解

现象:用 char(10) 存用户名,查询不带空格出错。 根因char(n) 总是补足到 n 个空格。 解决:用 textvarchar,PG 没性能差异。

案例 2:UUID v4 做主键性能差

现象:B-tree 索引膨胀,写入慢。 根因:UUID v4 完全随机,导致 B-tree 频繁分裂。 解决:用 UUID v7(带时间戳前缀),或 bigint + sequence。

案例 3:JSONB 字段没索引

现象WHERE payload->>'country' = 'US' 全表扫描。 根因:JSONB 字段默认无索引。 解决:建 GIN 索引 CREATE INDEX i ON t USING gin (payload).

案例 4:RLS 性能灾难

现象:开了 RLS 后查询慢 10 倍。 根因:RLS 是 row-by-row 检查;复杂的 USING 表达式未走索引。 解决:用 (select auth.uid()) 包一层,让 planner 物化。

-- ❌ BAD: 每次 row 都调用 auth.uid()
USING (auth.uid() = user_id)

-- ✅ GOOD: 物化
USING ((select auth.uid()) = user_id)

案例 5:vacuum 没跑导致表膨胀

现象:磁盘满,查询慢。 根因:autovacuum 没启用或被禁用。 解决:检查 autovacuum 设置,手动 VACUUM FULL(锁表)或 VACUUM(不锁)。

案例 6:连接数爆掉

现象FATAL: too many clients already根因:max_connections 设置过大或连接池未用。 解决:用 PgBouncer 限制连接数,应用层用连接池。

案例 7:full text search 慢

现象LIKE '%keyword%' 跑了 30 秒。 根因:LIKE 前缀模糊不走索引。 解决:用 tsvector + GIN 索引。

ALTER TABLE articles ADD COLUMN search_vector tsvector
  GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || body)) STORED;

CREATE INDEX idx_articles_search ON articles USING gin (search_vector);

-- 查询
SELECT * FROM articles
WHERE search_vector @@ to_tsquery('english', 'postgres & performance');

案例 8:timestamp 范围查询走错索引

现象WHERE created_at BETWEEN '2026-01-01' AND '2026-01-31' 慢。 根因:复合索引顺序错了(status, created_at,但 WHERE 没有 status)。 解决:加 CREATE INDEX i ON t (created_at),或用 partial index 优化。

案例 9:null 处理 bug

现象WHERE deleted_at IS NULL 没走索引。 根因:NULL 在 PG 索引中是特殊值。 解决:用 partial index WHERE deleted_at IS NULL,或改用 deleted boolean 字段。

案例 10:money 类型陷阱

现象:用 money 类型,跨币种出错。 根因money 是单币种固定类型。 解决:用 numeric(20, 4) + 单独 currency 字段。


八、性能基准

8.1 索引 vs 全表扫描(100 万行)

场景无索引B-tree 索引GIN 索引
等值查询800ms5ms-
范围查询800ms15ms-
JSONB 包含1200ms-20ms
数组 contains1500ms-30ms
全文搜索3000ms-50ms

8.2 OFFSET vs 游标分页(10 亿行)

OFFSET 时间游标时间
第 1 页5ms5ms
第 1000 页250ms5ms
第 10 万页30s+5ms

结论:深度分页必须用游标。

8.3 UPSERT vs INSERT+UPDATE

场景单独 INSERT+UPDATEUPSERT
100 万行60s15s
冲突率 1%90s20s
冲突率 50%180s35s

九、与其他 Skills 配合

Skill配合
clickhouse-ioOLAP 数据同步到 ClickHouse
backend-patternsAPI 层数据库访问最佳实践
database-reviewer (Agent)全库审查,调用本 Skill
supabase-admin (若有)Supabase 专属管理
verification-loop数据库迁移后验证

完整工作流:

database-reviewer (全库扫描)
  ↓
postgres-patterns (匹配规则)
  ↓
输出报告 (按严重度)
  ↓
人工确认 + 修复
  ↓
verification-loop (验证)

十、5 条反合理化

借口反驳
”ORM 自动 SQL 没事”ORM 生成的 SQL 经常有反模式
”索引越多越快”索引拖累写入,浪费空间
”text 和 varchar 一样”但 varchar(n) 仍可能产生性能问题
”OFFSET 简单够用”深度分页灾难
”RLS 性能损耗大”正确写法(物化 auth.uid())损耗 < 5%

十一、5 条实战技巧

  1. 生产前必跑反模式检测 SQL:把上面的 4 条 SQL 集成到 CI
  2. 启用 pg_stat_statements + auto_explain:自动捕获慢查询
  3. 所有外键必加索引:写 migration 时强制
  4. 数字主键用 bigint:避免 2038 年问题
  5. 金额一律 numeric:不存为 float

十二、Q&A

Q: 必须订阅 Claude Code 吗? A: Skill 在 Claude Sonnet/Opus 上效果最佳,其他 LLM 也可借鉴。

Q: 和 backend-patterns 区别? A: postgres-patterns 聚焦 SQL 和数据库本身;backend-patterns 聚焦 API 层。

Q: 跟 clickhouse-io 关系? A: Postgres = OLTP(事务),ClickHouse = OLAP(分析),可组合使用。

Q: 跟 Supabase CLI 关系? A: Skill 提供”知识”,Supabase CLI 提供”工具”(migration、db push)。

Q: 老的 schema 改造适用吗? A: 适合,配合 database-reviewer Agent 渐进式改造。

Q: 中文支持? A: SQL 关键字英文,注释和字段名可中文。

Q: 学习曲线? A: 中等。需懂 SQL 基础和 PG 概念。


十三、安装

# Claude Code
/plugin marketplace add affaan-m/everything-claude-code
/plugin install everything-claude-code@everything-claude-code
cp -r everything-claude-code/rules/common ~/.claude/rules/

# 通用
npx skills add affaan-m/everything-claude-code --skill postgres-patterns

十四、总结

核心价值

  • PostgreSQL 模式速查 + 反模式检测 SQL
  • Supabase RLS 安全配置
  • 索引策略、数据类型、高效分页
  • 真实踩坑案例

适用人群

  • 后端开发者(Node + Supabase / Rails / Django / Spring)
  • 数据工程师
  • Supabase 项目
  • AI 辅助生成 SQL 场景

投入产出比:⭐⭐⭐⭐⭐(5/5)—— 所有 PG 项目必装。

何时不要用

  • OLAP(用 clickhouse-io)
  • NoSQL(MongoDB / Redis 专属)
  • 嵌入式(SQLite 够用)
  • 没用过 PG(先学基础)

配套文档:clickhouse-io 分析 | backend-patterns 后端 | database-reviewer Agent


参考资料

  1. PostgreSQL 官方文档 — Index Types
  2. Supabase Docs — Managing Indexes in Postgres
  3. Supabase Row Level Security 指南
  4. PostgreSQL Wiki — Index Maintenance
  5. Use the Index, Luke! — PostgreSQL 索引教程

📦 快速安装

1 Git Clone
git clone https://github.com/affaan-m/everything-claude-code.git
cd everything-claude-code
ls skills/postgres-patterns