Django为每个filter()调用命中数据库

时间:2011-05-26 04:20:10

标签: database django performance django-queryset

我有一些Django 1.3代码,它在循环中查找许多模型实例,即

my_set = myinstance.subitem_set.all()

for value in values:
  existing = my_set.filter(attr_name=value)
  if len(existing) == 1:
     ...

这是有效的,但是分析SQL查询表明它在每次迭代时都会访问数据库。根据{{​​3}}迭代相关项目应该急切地加载它们,所以我试着调用:

list(my_set)

但是,这没有用。它确实执行查询以加载所有子项,但它仍然对循环内的每个子项执行单独查询。如何让它使用缓存集而不是每次都点击数据库?数据库是PostgreSQL 8.4。

1 个答案:

答案 0 :(得分:5)

问题出在这一行:

if len(existing) == 1:

来自Django文档:

  

LEN()。在您上面调用len()时会评估QuerySet。正如您所料,这会返回结果列表的长度。

     

注意:如果您只想确定集合中的记录数,请不要在QuerySets上使用len()。使用SQL的SELECT COUNT(*)来处理数据库级别的计数效率要高得多,而Django正是因为这个原因提供了count()方法。见下面的count()。

因此,在您的情况下,每次调用len(existing)时都会执行查询。更有效的方法是:

existing.count() == 1

每次调用它时,它也会命中数据库,但它会执行SELECT COUNT(*)更快。