Django Query 非常慢
Posted
技术标签:
【中文标题】Django Query 非常慢【英文标题】:Django Query extremely slow 【发布时间】:2013-07-31 23:48:44 【问题描述】:我的 Django 应用程序有问题。对模型 Scope 的查询非常慢,经过一些调试后,我仍然不知道问题出在哪里。
当我像scope = Scope.objects.get(pk='Esoterik I')
这样查询数据库时,需要 5 到 10 秒。数据库的条目少于 10 个,并且主键上有一个索引,所以它太慢了。在数据库上执行类似SELECT * FROM scope WHERE title='Esoterik I';
的等效查询时,一切正常,只需要大约 50 毫秒。
如果我查询像scope_list = Scope.objects.filter(members=some_user)
这样的一组结果,然后调用 print(scope_list) 或遍历列表元素,也会发生同样的问题。查询本身只需要几毫秒,但元素的打印或迭代再次需要 5 到 10 秒,但集合只有两个条目。
数据库后端是 Postgresql。同样的问题出现在本地开发服务器和apache上。
这里是模型的代码:
class Scope(models.Model):
title = models.CharField(primary_key=True, max_length=30)
## the semester the scope is linked with
assoc_semester = models.ForeignKey(Semester, null=True)
## the grade of the scope. can be Null if the scope is not a class
assoc_grade = models.ForeignKey(Grade, null=True)
## the timetable of the scope. can be null if the scope is not direct associated with a class
assoc_timetable = models.ForeignKey(Timetable, null=True)
## the associated subject of the scope
assoc_subject = models.ForeignKey(Subject)
## the calendar of the scope
assoc_calendar = models.ForeignKey(Calendar)
## the usergroup of the scope
assoc_usergroup = models.ForeignKey(Group)
members = models.ManyToManyField(User)
unread_count = None
更新
这是python分析器的输出。似乎 query.py 被调用了 160 万次 - 有点太多了。
【问题讨论】:
这个模型有__unicode__()
方法吗?可以发一下吗?
是的,它有:def __unicode__(self): return self.title
我建议安装Django Debug Toolbar 以便您可以单独查看每个查询。它会让你更好地了解是什么让你放慢了速度。
您是从 django shell 还是从某个角度进行测试? DEBUG
settings.py 中是真还是假?
您提到的两个环境是否都连接到同一个 PostgreSQL 服务器,如果是,您是否在数据库设置中使用主机名或 IP 地址?
【参考方案1】:
您应该先尝试找出问题所在。运行 manage.py shell 并运行以下命令:
scope = Scope.objects.get(pk='Esoterik I')
print scope
现在 django 查询只有在非常必要时才会执行。也就是说,如果您在第一行之后遇到缓慢,则问题出在创建查询的某个地方,这表明对象管理器存在问题。下一步是尝试通过 django 执行原始 SQL,并确保问题确实出在管理器上,而不是一般 django 中的错误。
如果您在使用第二行时遇到缓慢问题,则问题可能出在查询的实际执行上,或者与数据的显示\打印有关。您可以在不打印的情况下强制执行查询(查看文档)以找出它是哪一个。
据我了解,但我认为解决此问题的最佳方法是将流程分解为不同的部分,并找出导致缓慢的部分
【讨论】:
scope = Scope.objects.get(pk='Something')
和Scope.objects.get(pk='something')
展位时间相同。如果我使用 filter() 而不是 get() 我在执行查询时遇到性能问题(例如,如果我尝试使用查询集内容执行 print()),所以看起来查询是正确构建的,但在执行时间出了点问题
当我尝试进行原始查询时,执行需要同样很长时间。【参考方案2】:
为了确定数据库执行时间,最好测试 Django 生成的查询,因为 Django 生成的查询可能不是简单的SELECT * from blah blah
查看 Django 生成的查询:
_somedata = Scope.objects.filter(pk='Esoterik I') # you must use filter in here
print somedata.query.__format__('')
这将显示 Django 生成的完整查询。然后复制它并打开一个 Postgresql 控制台并使用 Postgresql 分析工具:
EXPLAIN ANALYZE <your django query here>;
喜欢:
EXPLAIN ANALYZE SELECT * FROMsomeapp_scope WHERE id = 'Esoterik I';
EXPLAIN
将显示平均执行数据,而ANAYLZE
还将向您显示有关该分析执行时间的一些额外数据。
您还可以在这些分析结果中查看 postgresql 在查询执行期间是否使用了任何索引。
【讨论】:
我试过了。 django 的原始查询需要 26 毫秒的执行时间,而简单的 SELECT * ... 需要 15 毫秒。所以看起来生成的sql不是问题以上是关于Django Query 非常慢的主要内容,如果未能解决你的问题,请参考以下文章
heroku 上的 Django 和 imagekit 保存到 AWS S3 非常慢
使用 Django-debug-toolbar 优化Query 提高代码效率