【问题标题】:Django QuerySet update performanceDjango QuerySet 更新性能
【发布时间】:2012-05-21 19:12:57
【问题描述】:

哪个性能更好?

我们取一片产品。这使我们无法批量更新。

products = Product.objects.filter(featured=True).order_by("-modified_on")[3:]

for product in products:
  product.featured = False
  product.save()

或(无效)

罢工>

for product in products.iterator():
  product.update(featured=False)

我也试过QuerySet的in语句如下。

Product.objects.filter(pk__in=products).update(featured=False)

这一行在 SQLite 上运行良好。但是,它在 MySQL 异常之后上升。所以,我不能用那个。

DatabaseError: (1235, "这个版本的 MySQL 还不支持 'LIMIT & IN/ALL/ANY/SOME 子查询'")

编辑: iterator() 方法也会导致重新评估查询。所以,这对性能不利。

【问题讨论】:

  • 你真正想要达到什么目的?你的第二个代码块没有意义。 iterator 默认不存在,这是你添加的吗?而且,一个实例没有update 方法,所以,这是你添加的吗?
  • 我的开发环境:Ubuntu 12.04、Python 2.7、Django 1.4、MySQL 5.5.22、python-mysqldb 1.2.3
  • 这不是你被问到的。
  • 其实我还没有实现迭代器和更新方法。它们带有 Django 框架的核心。
  • 好的。我错过了iterator(),但instance 上仍然没有update 方法。这仅在查询集上可用。

标签: django django-models django-queryset


【解决方案1】:

正如@Chris Pratt 在 cmets 中指出的那样,第二个示例是无效的,因为对象没有更新方法。您的第一个示例将需要等于 results+1 的查询,因为它必须更新每个对象。如果你有 1000 种产品,那可能真的很昂贵。理想情况下,如果可能,您确实希望将其减少到更固定的费用。

这与另一个问题的情况类似:
Django: Cannot update a query once a slice has been taken

话虽如此,您必须至少在 2 个查询中完成此操作,但您必须对如何构造 LIMIT 有点偷偷摸摸...

使用Q objects for complex queries

# get the IDs we want to exclude
products = Product.objects.filter(featured=True).order_by("-modified_on")[:3]
# flatten them into just a list of ids
ids = products.values_list('id', flat=True)

# Now use the Q object to construct a complex query
from django.db.models import Q
# This builds a list of "AND id NOT EQUAL TO i"
limits = [~Q(id=i) for i in ids]
Product.objects.filter(featured=True, *limits).update(featured=False)

【讨论】:

  • @TommasoBarbugli:你确定是一样的吗? Jan 尝试将有限的查询集直接传递给新的查询集。在此示例中,我使用 id 值列表。
  • 我在第二行遇到以下异常。 AttributeError:“QuerySet”对象没有属性“value_list”
  • @Jan:对不起,错字。应该是带有“s”的values_list
  • @jdi 解决了第二行的问题。但是,我在第三行收到以下消息.. DatabaseError: (1235, "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'")
【解决方案2】:

在某些情况下,可以将 QuerySet 缓存在数组中

products = list(products)
Product.objects.filter(pk__in=products).update(featured=False)

values_list

的小优化
products_id = list(products.values_list('id', flat=True)
Product.objects.filter(pk__in=products_id).update(featured=False)

【讨论】:

  • 你完全误解了我3年前的问题。
猜你喜欢
  • 2016-02-16
  • 2017-05-02
  • 2020-10-31
  • 1970-01-01
  • 2017-11-03
  • 2020-01-18
  • 1970-01-01
  • 2018-10-29
  • 2018-10-11
相关资源
最近更新 更多