优化Django获取查询

时间:2016-03-28 09:01:47

标签: django django-models query-optimization

我有类似的Django代码:

for obj in some_list:
    m1obj = Model1.objects.get(a=obj.a, b=obj.b, c=obj.c)
    Model2(m1=m1obj, d=obj.d, e='foo').save()

我确实使用Model2优化插入bulk_create,然而,由于来自get的{​​{1}}( ~45秒对于3k插入物。)

我也尝试添加:

Model1

class Meta: index_together = [ ('a', 'b', 'c'), ] unique_together = [ ('a', 'b', 'c'), ] 有点帮助,unique_together似乎没什么影响。

我有一个繁琐的解决方法:

  1. 过滤index_together以一个或多个键获取我需要的所有对象,例如Model1,并确保Django缓存结果,例如order_by('a', 'b')
  2. 使用二进制搜索(len())找到第一个from bisect import bisect_left然后找到a ...等(尽管bb更少s所以只是迭代是一样的。
  3. 这会将插入时间减少到超过 3秒

    必须有更好,更清洁和可维护的方法来做到这一点。有什么建议? 有没有办法在Django的缓存查询结果中过滤/获取(聪明地)?

    编辑:将c更改为d='foo' - 任何批量获取都需要映射到它所属的元组,否则我无法创建Model2条目。

2 个答案:

答案 0 :(得分:0)

您可以进行单个查询(如here所述),该查询只会获取您需要的结果,因此无需在以后进行排序和二进制搜索。

我没有测试过,所以我不知道它是否会比你现在做的更快。此外,由于SQL查询会很大(根据some_list中的记录数),因此如果查询超出MySQL设置中参数max_allowed_packet定义的大小,则此查询可能会引发错误(默认情况下为16MB {} 3}})。

import operator
from django.db.models import Q
query = reduce(operator.or_, (Q(a=obj.a, b=obj.b, c=obj.c) for x in values))
model1_objs = Model1.objects.filter(query)

然后,您可以使用bulk_create进行Model2

Model2.objects.bulk_create([
    Model2(m1=m1, d='foo', e='bar')
    for m1 in model1_objs
])

答案 1 :(得分:0)

Model1有多少行?如果它相对较小(小于50k)你可以使用过滤器获取所有,然后比较python中的元组。

“some_list”如何是小列表(小于100),如果是,你可以使用Q关键字一次过滤所有内容。

first = some_list.pop()
conditions = Q(a=first.a, b=first.b, c=first.c)
for obj in some_list:
    conditions |= Q(a=obj.a, b=obj.b, c=obj.c)

Model1.objects.filter(conditions)   # this will get your all the Model1 from ur list

Q object Ref:https://docs.djangoproject.com/en/1.9/ref/models/querysets/#q-objects