【发布时间】:2011-07-04 16:13:07
【问题描述】:
我经常发现自己想从 Django 的查询集中获取第一个对象,或者如果没有,则返回 None。有很多方法可以做到这一点,所有这些都有效。但我想知道哪个性能最高。
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
这会导致两次数据库调用吗?这似乎很浪费。这是不是更快?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
另一种选择是:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
这会生成单个数据库调用,这很好。但是需要在很多时候创建一个异常对象,当您真正需要的只是一个微不足道的 if 测试时,这是一件非常耗费内存的事情。
我怎样才能只用一个数据库调用而不用异常对象搅动内存?
【问题讨论】:
-
经验法则:如果您担心最小化数据库往返,请不要在查询集上使用
len(),始终使用.count()。 -
“经常创建异常对象,这是一件非常耗费内存的事情” - 如果您担心创建一个额外的异常,那么您做错了,因为 Python 使用到处都有例外。您是否真的对您的情况进行了基准测试,认为它是内存密集型的?
-
@Leopd 如果您实际上以任何方式(或至少是 cmets)对 anwser 进行了基准测试,您会知道它并没有更快。它实际上可能会更慢,因为你创建一个额外的列表只是为了把它扔掉。与调用 python 函数或首先使用 Django 的 ORM 的成本相比,所有这些都只是小菜一碟!对 filter() 的单次调用要比引发异常慢很多很多很多倍。
-
你的直觉是正确的,性能差异很小,但你的结论是错误的。我确实运行了一个基准测试,并且接受的答案实际上比实际速度更快。去图吧。
-
对于使用 Django 1.6 的人们,他们终于添加了
first()和last()便利方法:docs.djangoproject.com/en/dev/ref/models/querysets/#first
标签: python django performance django-models