我正在使用以下模型开展django项目。
class User(models.Model):
pass
class Item(models.Model):
user = models.ForeignKey(User)
item_id = models.IntegerField()
大约有1000万件物品和10万名用户。
我的目标是覆盖永久性的默认管理搜索 返回拥有" all"的所有匹配用户在合理的时间范围内指定的项目ID。
这些是我用来更好地说明我的标准的几项测试。
class TestSearch(TestCase):
def search(self, searchterm):
"""A tuple is returned with the first element as the queryset"""
return do_admin_search(User.objects.all())
def test_return_matching_users(self):
user = User.objects.create()
Item.objects.create(item_id=12345, user=user)
Item.objects.create(item_id=67890, user=user)
result = self.search('12345 67890')
assert_equal(1, result[0].count())
assert_equal(user, result[0][0])
def test_exclude_users_that_do_not_match_1(self):
user = User.objects.create()
Item.objects.create(item_id=12345, user=user)
result = self.search('12345 67890')
assert_false(result[0].exists())
def test_exclude_users_that_do_not_match_2(self):
user = User.objects.create()
result = self.search('12345 67890')
assert_false(result[0].exists())
以下代码段是我使用annotate
尝试超过50秒的最佳尝试。
def search_by_item_ids(queryset, item_ids):
params = {}
for i in item_ids:
cond = Case(When(item__item_id=i, then=True), output_field=BooleanField())
params['has_' + str(i)] = cond
queryset = queryset.annotate(**params)
params = {}
for i in item_ids:
params['has_' + str(i)] = True
queryset = queryset.filter(**params)
return queryset
我有什么办法可以加快速度吗?
答案 0 :(得分:0)
以下是一些快速建议,可以大幅改善效果。
在初始查询集上使用prefetch_related`获取相关项
queryset = User.objects.filter(...).prefetch_related('user_set')
使用__in
运算符进行过滤,而不是循环使用ID列表
def search_by_item_ids(queryset, item_ids):
return queryset.filter(item__item_id__in=item_ids)
请勿注释它是否已成为查询的条件
由于您知道此查询集仅包含item_ids列表中包含ID的记录,因此无需为每个对象编写该记录。
全部放在一起
只需致电 -
,您就可以大大加快您的工作速度queryset = User.objects.filter(
item__item_id__in=item_ids
).prefetch_related('user_set')
完整查询只有2 db命中。