一个页面,几十次数据库调用
一个原本很快的列表页,现在要一两秒,而且列表越长越糟。你去查每一条查询,单看都没问题。十条数据没事,一百条就不行了。
为什么很难看出来
这是 N+1,而且它诞生在一次渲染的内部:某处取了一个列表,然后为每一项再取一条关联记录。每条查询都是真的快,所以按请求计时抓不到它,代码评审也放过了它 —— 因为这段代码读起来完全合情合理。错的只有次数。
它更常随着重构而来,而不是随着新功能。把一次取数挪进一个「每行渲染一次」的组件里,是一行的改动,却把一条查询变成了和你行数一样多的查询。
Sixty 对此做了什么
数据库调用按渲染计数,并在版本之间比较,所以这条发现是「这个操作原本每次渲染一条查询,从这次部署起变成了十四条」,而不是一个还需要你去解读的延迟数字。调用栈会一起给出来,于是要负责的那个渲染被点了名。
这些证据会通过 MCP 送到你的编码助手那里:查询本身、调用栈、前后的次数,以及哪些子调用解释了这次变化。
它不做什么
按渲染计数需要一个服务端 agent,Node、Python、Go、Ruby 和 PHP 都有 —— 但只有 Node 不用你开口。它的构建期转换会自动为每个导出的异步函数开一个 span;其他语言里你需要标注值得测量的代码(Python 一个装饰器,Go 两行,Ruby 引入一个模块,PHP 一次调用),之后的归因是一样的。Java、.NET、Rust 和 Elixir 完全没有 agent。浏览器那一半配任何后端都能用,但它只看得到页面自己发出的请求。
OpenTelemetry
已经在使用 OpenTelemetry?
保留当前 Collector 和 exporter。Sixty 可以接入相连链路和有用的运行时指标,推断版本回归;有原生 agent 时,还能获得更深入的函数和数据库驱动细节。