在大部分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
1
ahcat 2016-08-15 12:45:41 +08:00 via iPhone
就这一句 select_related ,贴到正文就好了。
|
2
georgema1982 2016-08-15 12:51:40 +08:00 2
显然你对 django 的 orm 了解还不够深入,所以得出“只能解决单值关系的问题”这样的结论。多值可以通过 prefetch_related 来解决: https://docs.djangoproject.com/en/1.10/ref/models/querysets/#prefetch-related
|
3
ruandao 2016-08-15 13:37:31 +08:00
不建议用 orm
后面换工作你会吃亏的 |
4
tanteng 2016-08-15 13:46:15 +08:00
Laravel 的 ORM 有预加载概念
|
5
jy01264313 2016-08-15 13:57:30 +08:00
@ruandao 为什么不建议使用 ORM 呢?
|
6
NaVient 2016-08-15 14:41:51 +08:00
@jy01264313 他的意思应该是用好 SQL 语句,不管去哪都能用
|
7
lynnworld 2016-08-15 14:54:13 +08:00
eager load 和 lazy load
|
8
hantsy 2016-08-15 15:07:09 +08:00
fetch join.
|
9
ziXiong OP @georgema1982 多谢提醒,最近才开始关注 N+1 问题, prefetch_related 的文档我也看过,但是显然之前没有看懂。我在 shell 中打印 print(User.objects.prefetch_related('articles').all().query),发现只执行了一条查询所有 user 的 sql, 还没有预加载多值关系,就理解错了 prefetch_related 。现在发现是 QuerySet.query 的问题。 现在博客也已经修正了这个问题。
|
10
ziXiong OP @jy01264313 习惯了 ORM, 会让自己写 SQL 的能力变差吧。 不过业务量比较大的项目中,不用 ORM 也是白白增添了很多工作量。 就看使用者怎么平衡吧。
|
12
est 2016-08-15 15:21:52 +08:00 1
「不用 ORM 」 == 「修车太复杂了我不用干脆走路吧」
|
14
yzongyue 2016-08-15 15:27:13 +08:00 via Android 1
上缓存,要的就是 N+1 ,少用 join 之类的
|
17
jy01264313 2016-08-15 22:03:02 +08:00
@ziXiong 其实我个人感觉主要的业务都用 ORM ,但是报表一类的肯定还是 SQL 。
1. SQL 关键字都大写 2. 不用 SELECT * 这样的语法 3. 所有的表前面都加上库命,字段前面都加上表名,用 `` 来包裹 我看见的 SQL ,上一点都做不到,我觉得还是用 ORM 规范一点 |
18
chaegumi 2016-08-15 22:20:39 +08:00
复杂的查询 ORM 能胜任?还是直接 sql 会顺手很多
|
19
rainybowe 2016-08-15 22:40:30 +08:00
batch_select( https://github.com/lilspikey/django-batch-select)同样能解决 n+1 问题,针对单值以及多值关系。
|
20
fx 2016-08-15 23:18:00 +08:00
select in
|
21
georgema1982 2016-08-16 01:20:33 +08:00
@rainybowe 这个项目都 5 年之久没更新了,不建议使用。如果 django 自己的 prefetch_related 不能满足需求,我推荐另外一个项目: https://github.com/ionelmc/django-prefetch
|