Python中Django框架的order_by与select_related连用导致的性能问题如何解决?
数据库中有几张表通过外键关联的 现在我想将一些数据排序展示出来(涉及了几张表)
然后就碰到了如下情况
第一种:
orders = Order.objects.filter(**params).order_by('-created')
然后在模板中遍历,会导致查询很多次数据库
第二种:
orders = Order.objects.filter(**params).order_by('-created').select_related("source", "customer", "handler","source__handler")
这样减少查询次数但是查询时间超级久
第三种: 我将第二种里面的 order_by 取消掉后,也就是
orders = Order.objects.filter(**params).select_related("source", "customer", "handler","source__handler")
这种情况,查询效率就又正常了,可是数据不是排序的
然后在我百度了一下午之后发现这个博客写的好像和我的情况一样,链接
可是问题来了,我只会写简单 sql,这个 sql 实在是太复杂了,搞不定,请教下各位前辈,有没有办法直接用 ORM 就能解决
Python中Django框架的order_by与select_related连用导致的性能问题如何解决?
可以分成两步,先 order by 获取 ID 和 created,然后在关联查询和排序😀
这个问题很典型。order_by和select_related连用导致性能问题,通常是因为order_by排序的字段不在select_related预加载的主表上,而是关联表的字段。这会导致数据库无法高效利用JOIN,甚至可能产生大量临时数据排序,拖慢查询。
核心原因和解决方案如下:
1. 问题根源
当你写 Model.objects.select_related('foreign_key').order_by('foreign_key__field') 时,如果关联表数据量大,数据库需要对JOIN后的结果集进行排序,这个排序操作(filesort)可能非常耗时,尤其是在没有合适索引的情况下。
2. 解决方案
方案A:优化索引(治本)
确保被排序的关联表字段(foreign_key.field)上有索引。这是最有效的办法。
# 在关联模型上,例如RelatedModel的'field'字段添加数据库索引
class RelatedModel(models.Model):
field = models.CharField(max_length=100, db_index=True) # 添加db_index
# ... 其他字段
方案B:调整查询逻辑(治标) 如果无法加索引或数据量极大,可以拆分查询,利用Python进行排序。注意:这只在结果集相对较小时可行,否则内存压力大。
# 先预加载,再在Python中排序
queryset = Model.objects.select_related('foreign_key').all()
sorted_list = sorted(queryset, key=lambda x: x.foreign_key.field if x.foreign_key else '')
# 此时sorted_list是列表,不是QuerySet
方案C:使用Prefetch进行更精细的控制(高级)
如果关联关系复杂(如反向关联或多对多),使用prefetch_related配合Prefetch对象可能比select_related更合适,但order_by问题依然需要结合索引解决。
from django.db.models import Prefetch
queryset = Model.objects.prefetch_related(
Prefetch('foreign_key', queryset=RelatedModel.objects.only('id', 'field'))
).order_by('foreign_key__field') # 排序问题依旧,仍需索引
总结建议 优先给关联表的排序字段加数据库索引。
你可以把 select_related 改成 prefetch_related. 应该可以完美解决你的问题.
created 有索引吗?
有索引的 而且也生效了
感谢 我去尝试下
感谢 我去尝试下
#4
explain 打印下执行计划看看
感谢帮助 我确定不是索引的问题哈 问题就是我贴的链接里面的那个问题 已经解决 十分感谢
是怎么解决的呢

