内容提要
作者用30个模型测试PostgreSQL模式生成,发现编码智能体普遍过度建索引,尤其集中在写入最频繁的表上。16个索引使WAL写入增至1.8倍、更新耗时1.9倍,并破坏HOT更新、加重VACUUM和缓存压力。提示词“make it production-ready”会使索引数增加约两成。建议上线前检查未使用索引,避免在热表上盲目加索引。
延伸解读
索引数量与写入成本的权衡
文章通过基准测试表明,在写入频繁的表上,索引数量增加会显著提升WAL写入量和更新延迟。例如,16个索引导致WAL写入增至1.8倍、更新耗时1.9倍。但索引并非越少越好:在只读或追加型表上,索引几乎无代价。关键在于识别热表,并评估每个索引对写路径的实际影响,而非盲目追求索引最小化。
HOT更新失效的隐藏代价
当索引键包含被更新的列时,PostgreSQL无法使用HOT更新,导致每次更新都必须修改所有相关索引。文章测试显示,仅将一个索引放在被更新列上,就会使HOT更新比例从46.2%降至0%,更新耗时增加45%。因此,检查热表上索引的列位置比单纯控制索引数量更重要,尤其是像last_activity_at这样频繁变更的列。
提示词对模式设计的影响
文章发现,在提示词末尾添加“make it production-ready”会使生成的索引数量增加约20%。这一常见用语被模型解读为需要更全面的索引覆盖,却忽略了写入成本。这提醒开发者,与编码智能体交互时,提示词的措辞会直接影响数据库模式决策,应明确写入模式或要求评估现有索引。
上线前检查未使用索引
文章建议在生产环境中定期检查未使用的索引。通过查询pg_stat_user_indexes,可以找出扫描次数为0的索引,但需注意计数器可能因重启重置、副本可能使用主库未用的索引,以及唯一索引用于数据完整性。在删除前应结合业务查询模式判断,避免误删虽未扫描但必要的索引。
Q&A
为什么在PostgreSQL热表上添加过多索引会导致写入性能下降?
在热表上,每个索引都会在每次写入时增加额外工作。如果索引涉及被修改的列,会破坏HOT更新,导致每个索引都需要写入新条目,产生额外WAL记录,并增加VACUUM清理死元组的负担。例如,16个索引使WAL写入增至1.8倍,更新耗时1.9倍。
编码智能体生成的数据库模式通常会在哪些表上过度创建索引?
编码智能体倾向于将索引集中到写入最频繁的表上,例如帮助台系统的tickets表、健身系统的class_occurrence表、货运系统的loads表等。这些表承载核心数据,模型会针对每个过滤或排序需求添加索引,而不检查已有索引。
提示词“make it production-ready”对生成的索引数量有什么影响?
该提示词会使索引数量增加约20%。在实验中,添加该短语后,兽医应用索引数增加20%,货运应用增加17%。这三个词会显著影响最繁忙表的写入成本。
如何检查生产环境中未使用的索引?
可以查询pg_stat_user_indexes,找出idx_scan为0的非主键索引,并按索引大小排序。但需注意:计数器在重启后重置,副本可能使用主库忽略的索引,唯一索引用于数据完整性不能随意删除。
索引数量与WAL写入量之间的关系是什么?
WAL写入量跟踪的是索引占用空间和页面脏度,而非单纯的索引数量。例如,9个具有严格部分谓词的索引可能比7个宽泛索引产生更少WAL。但当索引数量达到15个时,WAL写入量可增至1.8倍。
在热表上,索引对缓存有什么影响?
当shared_buffers有限时,额外索引页会挤占堆缓存。实验显示,将shared_buffers从512MB降至128MB后,物理读增加6.7倍,缓存堆从35MiB降至9MiB,更新耗时差距从1.9倍扩大到2.1倍。