【发布时间】:2015-03-01 17:10:25
【问题描述】:
我是 Django 和数据库的新手,所以我试图对性能有所了解。具体来说,我想了解select_related() 是否按照我认为的方式工作。
这是我的模型的简化版本:
class User(models.Model):
short = models.CharField(max_length=255)
name = models.CharField(max_length=255)
class Comment(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
short = models.ForeignKey(User)
在我的模板中,我需要在评论标题旁边显示用户的简称。我的测试数据库大小有 1000 个用户和 19000 个 cmets。
起初,我按如下方式检索列表:
cmt_list = Comment.objects.all().order_by('title')
我的模板正在访问short 外键关系,这导致对数据库的额外命中。检索所有数据需要 ~30 秒。这太可怕了。
我知道这比原始 SQL 快得多,但我不知道如何通过 Django ORM 来做到这一点。所以,我使用了低级接口:
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT app_comment.title,app_user.short \
FROM app_comment,app_user \
WHERE app_comment.short_id=app_user.id \
ORDER BY app_comment.title"
)
raw_list = cursor.fetchall()
cmt_list = [ {"title":entry[0], "short":entry[1]} for entry in raw_list]
检索所有数据需要 ~233 毫秒。这正是我所期待的!
阅读更多文档后,我发现了 Django 中的 select_related() 功能。
所以,我试过了:
cmt_list = Comment.objects.all().select_related('short__short').order_by('title')
检索所有数据需要 ~1.3 秒。比原来的要好得多,但与原始 SQL 查询相比仍然很慢。
问题
我在使用 select_related()/Django ORM 的方式上做错了什么?我知道 ORM 会增加一些开销,但是 1.3s 与 233ms 似乎过多。或者,这是意料之中的,我只需要克服它?
我将如何使用 ORM 设计一个与我创建的原始 SQL 查询等效的查询?鉴于我对 select_related() 的了解,我的原始 SQL 查询和我的 Django 查询应该大致相同。 (Django 查询将抓取更多内容,但对于我的测试数据,不会检索到太多额外内容。)
【问题讨论】:
-
您可以通过打印
Comment.objects.select_related('short').order_by('title').query来查看生成的查询。 -
如果您想测试差异是否是由额外的数据开销引起的(例如,Django 正在获取
content),请查看.only()或.defer()。跨度> -
啊哈!我没有意识到看到 Django 正在做的查询是多么容易。这将使我的测试更容易。谢谢@KevinChristopherHenry。
标签: django sqlite django-queryset django-orm