2016-06-14 68 views
0

我正在與以下模型的django項目。和搜索與反向關係

class User(models.Model): 
    pass 

class Item(models.Model): 
    user = models.ForeignKey(User) 
    item_id = models.IntegerField() 

有大約1000萬個項目和10萬個用戶。

我的目標是覆蓋永久需要的默認管理搜索,而 會在合理的時間範圍內返回所有擁有「全部」指定項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

以下是一些可以大幅提升性能的快速建議。初始查詢集

使用prefetch_related`獲取相關項目

queryset = User.objects.filter(...).prefetch_related('user_set') 

__in運營商,而不是通過標識

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分貝命中爲完整的查詢。

+0

不幸的是,我需要檢索所有擁有指定項目標識符「all」的所有用戶,而不是所有擁有這兩個ID的用戶,因此'item__item__id__in'在我的情況下不起作用。 – k8tems