← 中文资源

简体中文版本

用 DataLoader 消除 N+1 查询

用 DataLoader 按请求批处理并缓存查询,使列表接口不再每行发一次查询。

阅读英文原文

目标

列表接口每行发一次数据库查询,随列表增长延迟成倍上升。本配方把单条查询包装为按请求创建的 DataLoader,把同一时刻的多次加载合并为一次批量查询并按 id 回填结果,随后通过查询日志确认从 N 次降为 1 次;提醒 DataLoader 必须按请求创建以防缓存串用户。

步骤要点

  1. 把单条查询包装为按请求创建的 DataLoader。
  2. 用查询日志确认查询次数从 N 降为 1。
  3. 按请求创建新的 loader 防止缓存串用户。
  4. 限制批量大小避免超大 IN 子句。
const userLoader = new DataLoader(async (ids) => {
  const rows = await db.query('SELECT * FROM users WHERE id = ANY($1)', [ids]);
  const byId = new Map(rows.map(r => [r.id, r]));
  return ids.map(id => byId.get(id) || null);
});

排错提示

  • 缓存跨请求会串数据,必须按请求创建。
  • 批量过大可能超出查询限制。
  • 每请求缓存只在单次请求内去重。

适用边界

  • 需要支持批处理的数据访问。
  • 大批量需限制。