大家在使用 ORM 时,是怎么处理 N+1 问题的?

2016-08-15 12:40:19 +08:00
 ziXiong

在大部分ORM(关系对象映射中)框架中,如果要获取N个Model的关联对象,一般要进行N+1次数据库的查询操作,而最佳的解决方案是一次查询就够了。这就是ORM的N+1问题。

总结了一篇 django 中处理 N+1 问题的文章,欢迎大家来讨论。 http://www.z1xiong.me/blog/2016/08/15/django-n-plus-one-problem.html

7433 次点击
所在节点    Python
21 条回复
ahcat
2016-08-15 12:45:41 +08:00
就这一句 select_related ,贴到正文就好了。
georgema1982
2016-08-15 12:51:40 +08:00
显然你对 django 的 orm 了解还不够深入,所以得出“只能解决单值关系的问题”这样的结论。多值可以通过 prefetch_related 来解决: https://docs.djangoproject.com/en/1.10/ref/models/querysets/#prefetch-related
ruandao
2016-08-15 13:37:31 +08:00
不建议用 orm
后面换工作你会吃亏的
tanteng
2016-08-15 13:46:15 +08:00
Laravel 的 ORM 有预加载概念
jy01264313
2016-08-15 13:57:30 +08:00
@ruandao 为什么不建议使用 ORM 呢?
NaVient
2016-08-15 14:41:51 +08:00
@jy01264313 他的意思应该是用好 SQL 语句,不管去哪都能用
lynnworld
2016-08-15 14:54:13 +08:00
eager load 和 lazy load
hantsy
2016-08-15 15:07:09 +08:00
fetch join.
ziXiong
2016-08-15 15:15:42 +08:00
@georgema1982 多谢提醒,最近才开始关注 N+1 问题, prefetch_related 的文档我也看过,但是显然之前没有看懂。我在 shell 中打印 print(User.objects.prefetch_related('articles').all().query),发现只执行了一条查询所有 user 的 sql, 还没有预加载多值关系,就理解错了 prefetch_related 。现在发现是 QuerySet.query 的问题。 现在博客也已经修正了这个问题。
ziXiong
2016-08-15 15:17:54 +08:00
@jy01264313 习惯了 ORM, 会让自己写 SQL 的能力变差吧。 不过业务量比较大的项目中,不用 ORM 也是白白增添了很多工作量。 就看使用者怎么平衡吧。
ziXiong
2016-08-15 15:18:54 +08:00
@hantsy 能不能再解释得详细点?
est
2016-08-15 15:21:52 +08:00
「不用 ORM 」 == 「修车太复杂了我不用干脆走路吧」
msg7086
2016-08-15 15:23:39 +08:00
@ruandao 不用 orm ,迁移数据库平台或者改逻辑的时候你会哭死…
yzongyue
2016-08-15 15:27:13 +08:00
上缓存,要的就是 N+1 ,少用 join 之类的
ziXiong
2016-08-15 15:31:50 +08:00
@yzongyue 恩,在大型项目中不鼓励外键和 join , 确实就没有 N+1 问题一说了。
est
2016-08-15 17:16:09 +08:00
@ziXiong 是的。大家都是 for 循环然后 select ... where id in ...
jy01264313
2016-08-15 22:03:02 +08:00
@ziXiong 其实我个人感觉主要的业务都用 ORM ,但是报表一类的肯定还是 SQL 。
1. SQL 关键字都大写
2. 不用 SELECT * 这样的语法
3. 所有的表前面都加上库命,字段前面都加上表名,用 `` 来包裹
我看见的 SQL ,上一点都做不到,我觉得还是用 ORM 规范一点
chaegumi
2016-08-15 22:20:39 +08:00
复杂的查询 ORM 能胜任?还是直接 sql 会顺手很多
rainybowe
2016-08-15 22:40:30 +08:00
batch_select( https://github.com/lilspikey/django-batch-select)同样能解决 n+1 问题,针对单值以及多值关系。
fx
2016-08-15 23:18:00 +08:00
select in

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/299367

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX