跳到主要内容

SQL 查询优化

关系数据库为何适合关联查询?​

  • 关系模型: 用行列表示实体属性,用显式关系连接数据,查询可以重新组合表而不改变原始布局;
  • SQL: 描述想要什么结果,由数据库选择执行方案,方便表达过滤、联接和聚合;
  • 事务约束: 常见关系数据库支持约束和事务,帮助应用维护业务规则,相关保证见 事务;
  • 优点: 通用查询、成熟管理工具和明确模式使数据易于理解和访问;
  • 代价: 复杂联接、模式迁移与大规模分布式写入可能增加性能和维护成本;
  • 原文示例: PostgreSQL、MySQL、MariaDB、Amazon Aurora,选型仍需依据具体负载;

物化视图怎样减少重复计算?​

  • 物化视图: 把查询结果提前计算并存储,下次读取结果而不是重复扫描、联接和聚合;
  • 适用条件: 相同复杂查询频繁执行,而且业务可以接受定义清楚的刷新时效;
  • 性能收益: 用存储和维护开销换取更快的查询,必要时还能只暴露数据子集并减少传输;
  • 新鲜度代价: 底表变更后视图需要刷新,刷新失败或延迟会让结果落后;
  • 与普通视图区别: 普通视图通常主要保存查询定义,物化视图保存结果,不能只因名称带“视图”就认为性能相同;
订单明细 → 定期或增量聚合 → 每日销售额物化结果
报表请求 → 读取物化结果

N+1 查询为什么会拖慢页面?​

  • N+1: 先查询 N 个对象,再为每个对象分别查询关联数据,导致一次页面请求触发 1+N 次数据库查询;
  • 典型来源: ORM 懒加载或 GraphQL resolver 逐个取关联实体,而没有合并访问;
  • 代价来源: 即使每次查询不慢,额外网络往返、解析和连接占用仍会累加;
  • 识别方法: 观察一次请求的 SQL 数量和重复结构,不能只看单条 SQL 的耗时;

如何用批量加载消除 N+1?​

  • 批量加载: 收集本次需要的关联 ID,一次取回并在内存按 ID 组装结果;
  • 联接选择: 当结果形状合适时也可用联接或预加载减少请求,但要避免一对多展开造成大量重复行;
  • DataLoader: 把同一轮 resolver 请求合并成批次,可同时做请求范围内的去重;
  • 隔离边界: 批量或缓存不能跳过用户权限检查,也不应把不同用户的授权结果无条件共享;