作者用免费模型(MonkeyCode)分析PostgreSQL慢查询日志生成索引建议,实测模型能写出比人工更好的SQL,但也会幻觉表名和重复索引。
一个免费模型能否在不付授权费、不需要人工盯着的情况下充当数据库顾问?我有疑虑,但我有一个更迫切的问题:一个 staging 数据库总是无法按时完成查询。所以在接下来的 48 小时里,我通过 MonkeyCode 的免费模型访问把慢查询日志交给了一个免费模型,在一台免费服务器上运行了整个流程,并对每一条建议都持怀疑态度,直到 EXPLAIN 证明其有效。
声明:本文是 MonkeyCode 产品推广的一部分。
我写了一个小 Python 脚本,每四小时在一台免费服务器上唤醒一次,从 pg_stat_statements 拉取最慢的查询,然后用严格的 prompt 把它们输入免费模型。输出必须是 JSON:表名、列清单、索引类型,以及每条建议的一行理由。脚本从不碰生产环境,只把结论写入本地 Markdown 报告,我会在喝咖啡时过一遍。
令人惊讶的不是模型能生成 SQL,而是它有时生成比我高压下写的还好的 SQL。但它也会 hallucinate(幻觉)不存在的表、提出重复的索引、完全忽略已有的部分索引。以下是经过两轮调优后效果最好的精确 prompt:
def build_prompt(existing_indexes, slow_queries):
return f"""
You are a Postgres performance advisor.
Existing indexes on relevant tables: {existing_indexes}
Slow queries (from pg_stat_statements): {slow_queries}
For each query, propose up to two CREATE INDEX strategies.
Return JSON: [{{"table": ..., "columns": [...], "type": "btree|partial|covering", "reason": ...}}]
"""
我通过对一张克隆的 staging 表运行 EXPLAIN (ANALYZE, BUFFERS) 来衡量每条提案。我的验证循环很简单:先捕获基准执行计划,创建建议的索引,再捕获新计划,然后判断这个变更是否值得其带来的写放大。
0–12 小时:初印象
第一批产生了 19 条建议。其中 11 条是合理的单列索引,5 条是已有索引的重复,还有 3 条引用了一张名为 users_archive 的表——这张表我在两个月前就删掉了。显然模型需要更好的上下文,所以我把每个候选表的 \d+ 输出加入了 prompt。
13–24 小时:部分索引时刻
上下文修复后,模型捕捉到了一个真实问题。我们 deliveries 表上有一个反复出现的 status 过滤查询,因为唯一索引在 created_at 上,它在扫描 420 万行。模型建议了一个在 WHERE status = 'pending' 上的部分索引,以 id 为 covering 列。在 staging 中扫描降为 bitmap heap scan,估计成本下降了约 80%。这一条建议就值回了整个实验。
25–36 小时:自信但错误
模型为一条 order-history 查询提出了一个 (customer_id, created_at DESC) 的复合索引。听起来很完美。但 EXPLAIN 显示 planner 忽略了这个索引,因为对 status 的过滤仍在强制 seq scan。模型没有办法看到查询 where 子句的细节,除非我明确提供完整的 SQL 文本。于是我把 prompt 改为要求完整的谓词,而不只是摘要。
37–48 小时:最后冲刺
到末尾,我在 staging 上应用了 4 条索引,并用 EXPLAIN 逐条验证。两条有用,一条冗余,一条中立。模型的命中率约为 50%,比随机好但远不足以在没有审核门槛的情况下直接使用。
上下文健忘症:当 prompt 超过几千个 token 时,模型会忘记已有的索引列表,开始重复推荐。
Schema 盲区:它曾建议在 status 上建一个独立索引,即使同一列上已有一个更具体谓词的部分索引。
没有写放大意识:模型从不问新索引是否会拖慢写入密集型表。这个权衡仍然是人类的决定。
给模型小而密的上下文:schema 定义、已有索引,以及它们完整谓词的前五条慢查询。每条查询不要让它提出超过两条索引,否则信噪比会崩溃。每条建议都要用 staged EXPLAIN 运行验证,如果要上生产环境,使用 CREATE INDEX CONCURRENTLY 并准备回滚方案。
谁不应该用这个
如果你的负载是写密集型的,每多一个索引都是对每次 insert、update、delete 的征税。如果没有 staging 环境,不要让免费模型替你设计索引。如果缺乏耐心去读第二意见,你会把本该是人类审核缺失的问题怪到模型头上。
48 小时后,我仍然相信数据库需要人类。但我也相信免费模型可以成为一个不知疲倦的草案生成器,它能抛出你可能太快忽略的想法。最棒的是模型从不疲倦、不要求加薪、也不会因为被你把它的复合索引换成更好的而尴尬。错误仍然是你的——索引也是。如果你在类似实验中有心得,我很想听听你实际采纳了多少条建议。