关于 querying-local-postgres
面向 PostHog 开发者的本地 PostgreSQL 只读查询指南,涵盖 SQL 查询、调试和执行计划分析,并要求所有连接强制只读。
主要功能
- 01仅允许只读 SQL 操作
- 02给出本地 PostgreSQL 连接方式
- 03支持 EXPLAIN 查询计划分析
- 04提供 PostHog 表与数据库提示
- 05说明查询结果的调试场景
适用场景
- 01检查团队、项目或功能标志记录
- 02排查迁移、约束或重复键问题
- 03分析 Django 查询的执行计划
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ posthog --skill querying-local-postgres安装后在 Claude Code 中输入/querying-local-postgres确认已加载。
详细介绍
查询本地 Postgres(只读)— PostHog 仓库
用户查询:$ARGUMENTS
范围: 本仓库使用 PostgreSQL 存储应用元数据(团队、项目、标志、Django 模型等)。分析事件数据 存储在 ClickHouse 中,而非 Postgres——对于 events 类问题,除非用户明确要求使用 Postgres,否则请使用 HogQL / ClickHouse 工具。
何时使用
- 用户要求查询数据库、检查表,或针对 Postgres 运行 SQL
- 调试:行级检查(例如为什么某个团队/项目/标志行看起来不对)、迁移、约束、重复键
- 性能:对 Django 或应用表执行只读
SELECT的EXPLAIN/EXPLAIN (ANALYZE, …)
说明
- 严格禁止变更——请参阅下方的“严格禁止变更”。如果用户要求任何写入或变更,请拒绝并说明此技能为只读。
- 将用户的问题转换为一条或多条只读 SQL 语句。
- 在运行前,在代码块中展示 SQL。
- 使用下方的命令模式运行(始终带有
PGOPTIONS='-c default_transaction_read_only=on',以强制只读连接)。 - 展示结果并给出简要解读(尤其是在用于调试或计划审查时)。
严格禁止变更
不要运行、建议或生成以下任何内容。 请拒绝并说明此技能为只读。
- DML:
INSERT、UPDATE、DELETE、MERGE、TRUNCATE - DDL:
CREATE、DROP、ALTER、RENAME - 其他写入:
COPY ... TO program、CALL(如果会变更)、GRANT/REVOKE - 对只读
SELECT以外的任何内容执行EXPLAIN ANALYZE(包括WITH … SELECT)。不要将 DML 包装在EXPLAIN ANALYZE中——那会执行写入。下方的只读连接会拒绝写入,但 Agent 不得尝试此模式。 - 任何修改数据、模式或角色的语句
允许:
SELECT(包括WITH … SELECT)EXPLAIN…SELECT(仅估算计划;不执行)EXPLAIN (ANALYZE, …) SELECT——会执行一次SELECT;仅用于性能分析。必须在下方的只读连接上运行。SHOW、从目录视图(pg_stat_*、information_schema等)执行SELECT,前提是只读
如果用户请求写入操作,请说:“此技能为只读。我无法运行 INSERT/UPDATE/DELETE 或其他变更。请使用数据库客户端或迁移工具进行写入。”
EXPLAIN 和 EXPLAIN ANALYZE(性能)
| 目标 | 使用什么 |
|---|---|
| 计划形态、估算成本、不执行 | EXPLAIN (FORMAT TEXT, COSTS) 或添加 VERBOSE |
| 实际耗时、行数、缓冲区命中 | 对 SELECT 执行 EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) |
| 缓冲区 + WAL 统计 | BUFFERS 需要 ANALYZE;WAL 需要 ANALYZE(PostgreSQL 13+) |
安全模式: 被分析的语句必须仅是 SELECT(或 WITH … SELECT),并在只读连接上运行(见下方“用法”)。示例:
PGOPTIONS='-c default_transaction_read_only=on' psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c "
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT TEXT)
SELECT … LIMIT 100;"
可选标志(在有用时):SETTINGS(显示非默认 GUC)、WAL(与 ANALYZE 一起使用)、TIMING(在较新版本中,ANALYZE 默认开启)。
注意事项:
EXPLAIN ANALYZE会运行查询——在大扫描上可能很慢或负载很重;在探索时,优先使用有界SELECT(例如符合生产形态的真实WHERE、LIMIT)。- 生产 / 共享数据库——分析热查询或宽查询可能增加负载;当用户在意影响时,优先使用预发布环境、副本或非高峰时段。
- 不带
ANALYZE的EXPLAIN——不会执行内部语句(某些特殊情况除外);仍然只能包装只读 SQL。
PostHog:连接和 DATABASE_URL
本地 Postgres(宿主机)——本技能的默认配置
日常本地查询请使用这个硬编码 URL(对应典型的 Docker Compose + 本地主机端口 5432,SSL 关闭):
| 设置 | 值 |
|---|---|
| Host | localhost |
| Port | 5432 |
| User | posthog |
| Password | posthog |
| Database | posthog |
| SSL | off |
# Prefer this unless the user says their local password/db differs
LOCAL_POSTGRES_URL='postgres://posthog:posthog@localhost:5432/posthog'
等价写法:postgresql://posthog:posthog@localhost:5432/posthog
同一服务器上的其他本地数据库:只需替换路径,例如 ...5432/posthog_persons。
配置的权威来源(应用): posthog/settings/data_stores.py(Django DATABASES、可选副本 POSTHOG_POSTGRES_READ_HOST、直连 POSTHOG_POSTGRES_DIRECT_HOST、PERSONS_DB_WRITER_URL,以及来自 products/db_routing.yaml 的产品数据库路由)。
当不使用硬编码 URL 时: 从宿主机使用相同凭据连接的做法记录在 Developing locally(fe_sendauth 排障)。确保容器正在运行。
DEBUG 开启时的默认环境变量: Django 会根据 PGHOST(默认 db)、PGUSER / PGPASSWORD、PGPORT、PGDATABASE 构建默认的 DATABASE_URL——与容器内主机名相匹配。从宿主机连接时,请使用 localhost 以及相同的用户名/密码/数据库名,除非你的 shell 已经导出了 DATABASE_URL。
多个 PostgreSQL 数据库(本地 compose 中为同一服务器;逻辑上相互独立的数据库):
- 主应用数据库:通常为
posthog - Persons 数据库:
posthog_persons(PERSONS_DB_WRITER_URL/PERSONS_DB_READER_URL) - 产品隔离数据库:按
products/db_routing.yaml为posthog_<name>(由docker/postgres-init-scripts/create-product-dbs.sh创建) - 其他初始化脚本可能会创建额外的数据库(例如 cyclotron)——如有需要,请查看
docker/postgres-init-scripts/
通过修改 DATABASE_URL 中的路径让 psql 指向正确的数据库(例如 .../posthog_persons)。
Rust / sqlx: 某些服务在 posthog/rust 下工作时使用 rust/.env 中的 DATABASE_URL——参见 rust/README.md。
用法(命令模式)
始终通过 PGOPTIONS='-c default_transaction_read_only=on' 强制连接为只读,这样即使生成的 SQL 有误,Postgres 也会拒绝写入。
为什么用
PGOPTIONS,而不是SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY? 包含多条语句的psql -c "..."字符串会作为单个隐式事务运行。SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY只设置_后续_事务的默认值——正在进行中的那个事务仍然保持 它在BEGIN时被赋予的读写模式,因此同一个-c中的写入操作不会被拒绝。PGOPTIONS='-c default_transaction_read_only=on'在连接启动时设置 GUC,因此每个事务(包括隐式的-c事务)都会以 只读方式开始。内联等价写法是在-c字符串中作为第一条语句执行SET TRANSACTION READ ONLY;(它影响当前事务,不同于SET SESSION CHARACTERISTICS)。
从 PostHog 仓库根目录运行,以便相对环境变量路径能够正确解析。
默认——本地硬编码 URL(posthog / posthog @ localhost:5432 / 数据库 posthog):
PGOPTIONS='-c default_transaction_read_only=on' psql "postgres://posthog:posthog@localhost:5432/posthog" -v ON_ERROR_STOP=1 -c "SELECT 1;"
方案 A——DATABASE_URL 已在 shell 中(例如执行 flox activate 或手动 export 之后):
PGOPTIONS='-c default_transaction_read_only=on' psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c "SELECT 1;"
方案 B——从仓库根目录下被 gitignore 的环境变量文件加载(如果那里设置了 DATABASE_URL):
npx dotenv -e .env -- bash -c "PGOPTIONS='-c default_transaction_read_only=on' psql \"\$DATABASE_URL\" -c 'SELECT ...'"
- 在 shell 内的 SQL 中照常使用单引号表示字符串字面量;在
-c中嵌套引号时要小心转义。 - 除非用户另有指定,否则默认
LIMIT 100。 - 对于宽行请使用
-x:psql ... -x -c "..."。
Schema 参考(PostHog)
- Django 模型 → 表: 参见
posthog/models/(以及products/下的产品包)。表名通常以posthog_为前缀并使用蛇形命名(例如posthog_team、posthog_user)。可在 psql 中用\dt posthog_*确认,或检查模型的Meta.db_table(如果非标准)。 - 迁移:
posthog/migrations/(以及产品迁移路径)随时间定义了权威的 DDL。 - Person 表名: 可通过
PERSON_TABLE_NAME配置(参见data_stores.py);默认为posthog_person。
使用查询运行器进行调试(PostHog 风格)
- 确认某个 team、project、user 或 feature-flag 关联存在对应行;在适用的情况下检查软删除 /
deleted字段。 - 将计数和 join 与应用的假设进行对比(例如 membership、project access)。
- 仅当用户连接到正确的主机时,才验证副本与主库读取差异(副本:
POSTHOG_POSTGRES_READ_HOST)。 - 对以 SQL 复制的慢 Django 查询的
SELECT使用EXPLAIN ANALYZE—— 注意会加载生产规模的数据。
交叉引用
- 本地设置和 DB 注意事项:
docs/published/handbook/engineering/developing-locally.md - 仓库 CLI:
hogli(参见.agents/skills/hogli/SKILL.md)