面向 Node 服务
哪个函数、哪条查询、哪次部署。
一个 agent,一条命令装好,测量每一个导出的异步函数和你的应用发出的每一条查询 —— 而且知道是哪个函数发出了哪条查询。每个版本都会和上一个作比较,所以发现指向的是你的部署,而不是某个小时。
它测量什么
- 每一个导出的异步函数
- 它花了多久,其中有多少是它自己的代码、而不是它调用的东西。「是我的代码变慢了,还是我调的东西变慢了」在这里是一个数字,而不是一个下午。
- 五种客户端上的每一条查询
- pg、mysql2、postgres.js、MongoDB 驱动和 Prisma —— 自动找到并埋点,包括穿过 Mongoose,以及在负载下穿过连接池。返回行数、列数、响应大小,以及对 MongoDB 而言,一次读取实际上走了多少个网络往返。
- 哪个函数发出了哪条查询
- 正是这一部分让其余的东西值得读。一条查询会记在它上面那个函数头上,所以 N+1 会出现在带着循环的那个函数上,而不是摊在一条一直看起来都没问题的查询上。
- 数据库为了回答做了什么
- 会向 Postgres 索要每条语句的执行计划 —— 而且从不绑定参数,所以不涉及你的任何一个值。MySQL 则改从 performance_schema 读取:每返回一行扫描了多少行,以及到底有没有用上索引。两者都以同一条发现的形式抵达:这条语句在不走索引地读那张表。
- 你的 HTTP 路由,进和出
- 处理了多少请求,以及花了多少时间在等别人的 API —— 于是一个慢的第三方不再被报告成「你的代码慢」。
它能找到什么
这里的每一项都会和上一个版本作比较,所以发现指向的是那次改动,而不是某一天。
上个版本还没有的 N+1
一个原本每次请求发一次数据库调用的函数,现在发十四次。锚定在部署上,所以它点名的是引入它的那个版本。
一条开始读整张表的查询
每次调用的行数从 30 变成了 30,000。在一个数据量像 staging 那样、又已经热起来的数据库上,这几乎不占时间 —— 然后一周之后它把生产环境压垮。
一条不再走索引的查询
这里唯一一条点名原因而不是症状的发现。它常常在还没有任何东西变慢时就到了:表还小到全表扫描也无所谓,而几周之后,当它不再小时,这就成了一次故障。
你自己的代码在变慢
花在函数自身里的时间,而不是花在它调用的东西上 —— 分开列出,好让你第一次就打开对的文件。
一次读取变成了几百次网络等待
MongoDB 是按批返回游标的。当一个结果集超过一批时,一次读取就变成几十甚至几百次连续往返 —— 文档完全一样,所以系统里除了时钟什么都没动。
某个东西现在被放在循环里调用
每次调用没有变化 —— 同样的速度、同样的数据 —— 但被调用了几百次,而以前只调用一次。
一条悄悄什么都不返回的查询
成功了,没有报错,也不慢,只是从原本有行变成了空。这类服务最常见的损坏方式,是让数字变小,而不是变大。
你的动态里会出现什么
不是一块需要你去读的仪表盘。每条发现一张卡片,上面有数字、有改变了它们的那个版本,还有你的编码助手写出修复所需要的证据。
这些是 `pnpm e2e` 打印出来的数字,在任何人克隆的这个仓库上都一样。它准备一个服务,发布一个带着两个真实回归的版本,然后把它们检测出来 —— 所以这里没有一个数字是我们挑的。
orders.getUserOrders重构的时候丢了一个 WHERE 子句,于是这个函数把整张表拉下来,再用 JavaScript 过滤。在一个热的数据库上,时钟几乎没动。
自版本 v2 起,对比 v1
orders.enrichOrders一条查询被挪进了循环里。每一条都很快,所以单看任何一次请求都没问题 —— 变的只有次数。
自版本 v2 起,对比 v1
如何安装
把它交给你已经开着的编码助手。它会读你的仓库,判断这意味着一份 Next 配置、一个 Vite 插件还是一条启动命令,然后接进去 —— 接着在同一段对话里,把找到的问题修掉。
claude mcp add sixty \
-e SIXTY_API_KEY=sixty_sk_… \
-e SIXTY_ENDPOINT=https://ingest.sixty.sh \
-- npx -y @sixty-sh/mcp
# or by hand, in your server entry:
import { init } from '@sixty-sh/node'
init()版本标识会自动从 Vercel、Render、Railway、Fly、Heroku 或 GitHub Actions 拿到。第一次比较会在你下一次部署之后到来,因为一个版本没有可比的对象。
它不做什么
- MySQL 和 MongoDB 不上报执行计划树。MySQL 的 EXPLAIN 需要真实的参数值,MongoDB 的 explain 需要真实的过滤条件,而这个 agent 一看到值就丢掉 —— 所以对 MySQL 它改从 performance_schema 得出结论,对 MongoDB 目前还没有。
- 异步生成器会被构建期转换跳过。把它包起来,测到的会是「调用方拿到迭代器之前用了多久」,那不是任何人想要的数字。
- agent 只能测量它从 JavaScript 够得着的东西。花在原生模块里、或者花在另一个进程里的时间,它只能当作等待来看。
如果你是因为下面某一条来的
看看你的上一次改动做了什么。
试试看!在做别的东西?可以看看 Python 服务、Lovable 应用、React Native 应用 —— 那些页面不一样,我们能看到的东西也不一样。