1
namelosw 2021-03-31 23:24:53 +08:00
另外一个没用过,不过 GraphQL 里面常用的 Dataloader 的原理是本来 lazy load 的时候打到 Dataloader 上,记下 id 最后一次执行,本质上并不是直接解决 N + 1,而是把 N + 1 batch 起来,生成很大的 SELECT IN (1, 2, 3 ...)。
而最常见防止 N + 1 的方式就是关闭 Lazy load,然后手动 prefetch —— 效果是放在一条 join 里,比上面一种方法要高效,但是程序员的活多了。 我猜最理想的方式是用类似程序分析的形式把 N + 1 转化成 join 而非 batch,不过感觉好像并不是 non-trivial 的问题,即使能实现限制也很强。 |
2
SakuraSv OP @namelosw 其实上面说的第二种方法(预加载)就是利用 Join 的办法,先判断你是否要获取这个字段,如果需要这个字段就调用特定的 SQL 进行级联,所以我感觉这两种方法都可以,但是不太清楚在具体场景中怎么去选择,所以来向大家咨询经验。
|
3
namelosw 2021-04-01 09:48:45 +08:00
@SakuraSv GraphQL 的设计导致了 N + 1 一上来就会满天飞,不可能全手动 join 和 prefetch,所以 Dataloader 是用 batch 平衡性能和代码复杂度的主要方式。
第二种的问题就是性能稍微好一点,不会出现巨型 SELECT IN 。但是你需要手动先帮框架 load 一部分,而不是靠 Dataloader 自动完成的。 我理解场景的话就是看你注重开发体验可读性 (Dataloader),还是注重性能优化 (pre-loading)。 |
4
SakuraSv OP @namelosw 刚才想到可以利用数据库的视图来间接实现第二种方式,虽然性能可能会比选择性 join 更差一点,但是可读性和性能应该能取到一个相对均衡的点
|
5
namelosw 2021-04-01 10:38:05 +08:00
|
6
obwj 84 天前
graphql 一定要用 dataloader
|