优化Django:嵌套查询 vs 关联查找

5
我有一段使用嵌套ORM查询的遗留代码,它生成带有JOIN的SQL SELECT查询和包含SELECT和JOIN的条件。执行这个查询需要很长时间。顺便说一下,当我在原始SQL中执行这个查询时,从中获得,它的执行时间是合理的。 在这种情况下,最佳优化实践是什么? 如果我使用ManyToMany和ForeignKey关系,查询会更快吗?

如果您说手动运行相同的SQL代码可以正常运行,那么您不需要优化该代码。 - wRAR
问题在于该查询服务用于获取具有指定参数的目录中的项目,并且它使用CMS模型,该模型具有一些自己不太容易理解的特定功能。 - user2115719
2个回答

9
在Django中,性能问题通常是由于在循环中跟随关系导致多个数据库查询引起的。如果你安装了django-debug-toolbar,你可以检查你正在执行多少个查询,并找出哪个查询需要被优化。调试工具栏还显示每个查询的时间,这对于优化Django至关重要,如果你没有安装或使用它,那么你会错过很多东西。
一般情况下,你可以通过使用select_related()prefetch_related()来解决跟随关系的问题。
一个页面通常应该最多有20-30个查询,再多就会严重影响性能。大多数页面只应该有5-10个查询。你想减少查询次数,因为往返是数据库性能的头号杀手。总的来说,一个大查询比100个小查询更快。
数据库性能的第二大杀手很少出现问题,尽管有时由于减少查询数量的技术而出现。如果您的查询太大,那么您应该使用defer()或only(),这样您就不会加载大型字段,因为您知道您不会使用它们。

需要我优化的网站主页面加载了400多个查询 :) - user2115719
1
是的...这太多查询了。太多了。我们需要查看您的模型、模板和视图,才能告诉您更好的方法。 - Jack Shedd
@user2115719:我同意这是太多的查询,请尝试使用select_related或prefetch_related预加载相关对象。 - Lie Ryan
它们不是我的,这是遗留代码! :) 我实际上找到了它们是如何生成的。甚至在我分析网站之前 - 这并不难猜测 - 有一个“热”循环,所有混乱都发生在那里。实际上,我写错了问题 - 这不是因为长页面加载而导致的重查询,而是因为那个循环。当我手动分析时,我误导了自己,在代码中放置标志 - 我只是放错了标志,并测量了整个循环的时间,而不仅仅是查询评估的时间。对不起 Django! :) - user2115719
顺便提一下 - 网站运行在 Django 1.3 上 - 它没有 prefetch_related() - 是否有可能手动制造预取?例如,如果我写 - items.objects.values('related__value') - 是否类似于 prefetch_related() - user2115719
@user2115719:是的,你可以这样做。prefetch_related 的作用是创建第二个查询来查询 related_value,然后将其作为第一个查询结果的属性进行赋值。这样使用两个查询而不是 n+1 个查询。请参见 http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/ 获取更详细的解释。 - Lie Ryan

5

当有疑问时,请使用 原生 SQL。在Django世界中,这是一种完全有效的优化方法。


1
我一直很害怕说出这句话,因为我认为它是我不可告人的秘密。 - GordonsBeard
1
嗯,数据库独立性通常是个笑话。 - Jack Shedd
3
@JackShedd说:对我来说不是这样,我通常使用sqlite进行开发,并部署到MySQL上。我甚至曾经将一个中型的 django 应用原本设计为 sqlite 和 MySQL 的应用无需更改任何应用代码就部署到了 Postgre 上,该应用以前在 Postgre 上也从未经过测试。 - Lie Ryan
2
为什么会感觉奇怪呢?数据库独立性是可能的吗?通常是什么阻碍了你实现数据库独立性? - Lie Ryan
3
没有人会关心这个。数据库独立性是ORM抽象的副作用,而不是它的目标。将其作为目标完全没有意义。每个RDMS(甚至SQLite)都有自己的性能/特性细节,可以用来产生巨大的性能提升、简化模型、提高数据完整性等等。关心数据库独立性就等于说,“我只想使用我的数据库能力的子集”。ORM的存在是为了让简单的事情变得更简单,而不是使复杂的事情变得不可能。 - Jack Shedd
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接