V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
SakuraSv
V2EX  ›  GraphQL

关于 N+1 问题解决方案的疑问

  •  
  •   SakuraSv · 2021-03-31 22:46:14 +08:00 · 1799 次点击
    这是一个创建于 1364 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在使用 Net.flix 的 DGS 框架写一个 GraphQL 服务,因为我对 GraphQL 实践经验不是很多,因此在处理 N+1 问题时产生了一些疑问。
    在官方文档 Async Data Fetching 一章中( https://net.flix.github.io/dgs/data-loaders/),DGS 提供了 DgsDataLoader 来提供合成查询的方式解决该问题。
    在文档另一章 Nested data fetchers ( https://net.flix.github.io/dgs/advanced/context-passing/)的 Pre-Loading 部分中又介绍了通过 DataFetchingEnvironment 获取 SelectionSet 并判断查询语句中是否有该子字段的方式提供预加载,我感觉这个方法也能解决 N+1 问题。
    那么这两种方法有什么不同的适用场景吗,还是我对他们理解有问题呢?
    ---
    因为网飞这个词被屏蔽了,所以上面链接 net 和 flix 那个点要删掉
    6 条回复    2024-09-29 17:06:57 +08:00
    namelosw
        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 的问题,即使能实现限制也很强。
    SakuraSv
        2
    SakuraSv  
    OP
       2021-04-01 08:51:28 +08:00
    @namelosw 其实上面说的第二种方法(预加载)就是利用 Join 的办法,先判断你是否要获取这个字段,如果需要这个字段就调用特定的 SQL 进行级联,所以我感觉这两种方法都可以,但是不太清楚在具体场景中怎么去选择,所以来向大家咨询经验。
    namelosw
        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)。
    SakuraSv
        4
    SakuraSv  
    OP
       2021-04-01 10:27:04 +08:00
    @namelosw 刚才想到可以利用数据库的视图来间接实现第二种方式,虽然性能可能会比选择性 join 更差一点,但是可读性和性能应该能取到一个相对均衡的点
    namelosw
        5
    namelosw  
       2021-04-01 10:38:05 +08:00
    @SakuraSv

    N + 1 是 application 的问题,视图只是在数据库里面的东西,我理解建了视图 application 也不知道,还是要发 N + 1 条 query…
    obwj
        6
    obwj  
       86 天前
    graphql 一定要用 dataloader
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1050 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:53 · PVG 03:53 · LAX 11:53 · JFK 14:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.