跳到主要内容
模型们一共提了 41 个不过关的索引

模型们一共提了 41 个不过关的索引

林默
林默

· 阅读约 5 分钟

那天晚上我干的事很傻:给一个模型丢了一条慢查询,让它帮忙提索引建议。它很快吐回来三条 CREATE INDEX,我盯着这几行看了一会儿,忽然发现自己判断不了它们到底有没有用。看起来都对,但没有一条能让我安心直接合进去。

先停一下,问个问题:判断一个索引建议好不好,标准在哪?

我一开始想得特别简单:加了之后查询快没快。快很多就是好索引,快一点就是一般,没快就是烂。后来被一个数字打醒了。有一条查询,加了索引之后从 14.2 毫秒降到 12.19 毫秒,快了差不多 17%。这算有效吗?单看数字你会说有点用。但执行计划翻出来,这个索引从头到尾没被采用过。那点加速只是热缓存和测量噪音之间的差,不是这个索引带来的。

想通这一层,那个把索引建议交给数据库裁决的小工具的思路就顺了:别让模型当裁判,也别让我当裁判,让数据库当裁判。做法是把建索引这件事塞进一个事务里,BEGIN 完建好索引、跑一遍 ANALYZE、再用 EXPLAIN (ANALYZE, BUFFERS) 测量,最后 ROLLBACK。索引在数据库里从没真正存在过。代价呢?CONCURRENTLY 没法在事务里跑,只能砍掉;回滚事务里建索引照样要加真实的锁,也会产生真实的写开销——但这本来就是验证,不是让你直接上生产。

验证要两个条件同时满足。一是查询有实质性的加速,二是执行计划真的选中了这个新索引。规则不复杂,但管用。那个 14.2 到 12.19 的例子就栽在第二条上——没被采用,加速多少都白搭。

再往下呢?我本来以为到这儿就结束了。一个让数据库当裁判的工具,把模型提的建议筛一遍,这不就解决了吗?

结果有两条查询让我又坐不住了。

整个实验里有八条查询,九个模型对其中六条都给出了有效索引,改善的恰好是同样六条。剩下两条,模型们加一块提了 41 个索引,全部没通过验证。对,41 个,一个没活下来。

这两条查询有个共同点:它们都要先跨过大半张表做聚合,再连接。一条是扫几十万条订单按国家统计营收,另一条是按消费额给团队套餐客户排序。这种查询要读的几乎是所有行,不是跳过行——索引帮不上忙,顺序扫描才是规划器的正确决定。

但没有任何一个模型承认这一点。它们只会接着给索引建议,而且给得很像那么回事。三个模型各自独立提了两份几乎相同的方案:一个是在 orders(status, placed_at) 上建覆盖索引,一个是在 users(id) 上携带 country 列。听着都挺专业,结果全被拒了。

你可能会说,三个模型都想到一块去了,这不说明方案靠谱吗?恰恰相反。这只能说明它们背了同一条训练建议,而不是各自独立想明白了。当训练分布里全是“查询慢就建索引”的正例,它们很难学到“这个查询慢是因为要读全表,所以别乱建”这种反例。模型擅长的是给建议,不擅长的是判断一个建议在自己的前提之外还成不成立。

跟这个绑在一起的还有一个更扫兴的数据:通过率跟价格高低没关系。九个模型价格从每百万输入 token 0.05 美元到 0.9 美元,差 18 倍;但建议通过率全都在 58% 到 67% 之间挤着。一个 550B 的推理模型,花掉的钱是一个 14B 模型的 23 倍,验证通过的索引却不到人家一半。它的问题不在索引建议本身——它一共只提了 7 个,7 个全过——它的问题是贵得没道理。它把推理过程也按输出 token 计费,光解释自己的思考就烧掉 14196 个 token,还有三条查询因为 3000 token 的输出预算被思考部分耗尽,最后连一条 CREATE INDEX 都没写出来。空回复,照样扣钱。

这个细节把我逗笑了,也让我有点警惕:我们可能会在“贵模型更可信”的幻觉里,为它更长的解释付钱。但解释长度和判断质量,在这组实验里一丁点正相关都没有。真正帮我把哪些索引该留判断清楚的,是那个默默回滚事务的数据库,不是模型的自信。

所以说回来,那天晚上我面对那三条 CREATE INDEX 时的犹豫,根子不在我不懂索引,在我试图把判断交出去——交给一个只会给加法、不会给减法的系统。这个实验最值钱的一句话,不是 151 个索引一共花了 5.5 美分,而是作者最后那句我盯着看了很久:建议很便宜,判断哪个建议值得信任才贵。而“判断哪个建议值得信任”这件事,过去在代码评审里我们手头只有 diff、没有执行计划,其实就是在猜。

再往下还有一个我还没想明白的问题:怎么让 agent 把“这里不该建索引”也当成一个有效答案?现在模型只能给加法,不能给减法。你得给它一个裁判,才能把减法逼出来。但减法本身该长什么样,怎么训练、怎么提示,我说不清。先放到这儿,下次接着剥。

林默
林默

从具体轶事入口,一问一答把默认对的判断剥到设计权衡,主动暴露走过的弯路。

查看主页 →