Django 非常大的反向外键查询
Django very large reverse ForeignKey query
我正在使用 Django admin 根据对象的反向 ForeignKey
对象字段值过滤对象。 App
有一个 ForeignKey
到 Contact
,我正在尝试通过 Django 管理中的 Apps
类别过滤 Contacts
。问题是查询非常大,我收到超时错误。大约有 30 万个联系人对象和大约 100 万个应用程序。 Django 管理中每页有 500 个结果。添加了数据库索引和 prefetch_related。我还应该做些什么来优化 Django 管理?我正在使用 sqlite 数据库。
代码:
class App(models.Model):
contact = models.ForeignKey('Contact', related_name='apps', null=True)
category = models.TextField(blank=True, null=True, db_index=True)
store = models.IntegerField(choices=STORE_TYPES, db_index=True)
class Meta:
index_together = [
['category', 'store'],
]
# admin:
class ContactAdmin(admin.ModelAdmin):
list_filter = (
AppCategory,
)
def queryset(self, request):
return super(ContactAdmin, self).queryset(request).prefetch_related(
'apps',
'to_contact',
)
# the main list_filter that is causing troubles:
class AppCategory(admin.SimpleListFilter):
title = 'app category'
parameter_name = 'app_category'
def lookups(self, request, modelAdmin):
return [
('Action', 'Action'),
('Adventure', 'Adventure'),
('Arcade', 'Arcade'),
('Board', 'Board'),
('Books', 'Books'),
('Books & Reference', 'Books & Reference'),
('Business', 'Business'),
('Card', 'Card'),
('Casino', 'Casino',),
('Casual', 'Casual'),
('Catalogs', 'Catalogs'),
('Comics', 'Comics'),
('Communication', 'Communication'),
('Education', 'Education'),
('Educational', 'Educational'),
('Entertainment', 'Entertainment'),
('Family', 'Family'),
('Finance', 'Finance'),
('Food & Drink', 'Food & Drink'),
('Games', 'Games'),
('Health & Fitness', 'Health & Fitness'),
('Libraries & Demo', 'Libraries & Demo'),
('Lifestyle', 'Lifestyle'),
('Media & Video', 'Media & Video'),
('Medical', 'Medical'),
('Music', 'Music'),
('Music & Audio', 'Music & Audio'),
('Navigation', 'Navigation'),
('News', 'News'),
('News & Magazines', 'News & Magazines'),
('Personalization', 'Personalization'),
('Photo & Video', 'Photo & Video'),
('Photography', 'Photography'),
('Productivity', 'Productivity'),
('Puzzle', 'Puzzle'),
('Racing', 'Racing'),
('Reference', 'Reference'),
('Role Playing', 'Role Playing'),
('Shopping', 'Shopping'),
('Simulation', 'Simulation'),
('Social', 'Social'),
('Social Networking', 'Social Networking'),
('Sports', 'Sports'),
('Strategy', 'Strategy'),
('Tools', 'Tools'),
('Transportation', 'Transportation'),
('Travel', 'Travel'),
('Travel & Local', 'Travel & Local'),
('Trivia', 'Trivia'),
('Utilities', 'Utilities'),
('Weather', 'Weather'),
('Word', 'Word')
]
def queryset(self, request, queryset):
if not self.value():
return queryset
else:
qs = queryset.filter(
apps__category=self.value()
)
return qs
我找到了答案。如果您过滤一个反向 ForeignKey
关系(在本例中为 apps__category
),一切正常。但我忘了说,我在 Django 管理页面的右侧组合了两个过滤器——另一个也是反向 ForeignKey
- apps__store
。当您这样做时,会执行两个完全相同的 INNER JOIN
,这会导致服务器超时。当我单独使用这些过滤器时,一切正常。
我正在使用 Django admin 根据对象的反向 ForeignKey
对象字段值过滤对象。 App
有一个 ForeignKey
到 Contact
,我正在尝试通过 Django 管理中的 Apps
类别过滤 Contacts
。问题是查询非常大,我收到超时错误。大约有 30 万个联系人对象和大约 100 万个应用程序。 Django 管理中每页有 500 个结果。添加了数据库索引和 prefetch_related。我还应该做些什么来优化 Django 管理?我正在使用 sqlite 数据库。
代码:
class App(models.Model):
contact = models.ForeignKey('Contact', related_name='apps', null=True)
category = models.TextField(blank=True, null=True, db_index=True)
store = models.IntegerField(choices=STORE_TYPES, db_index=True)
class Meta:
index_together = [
['category', 'store'],
]
# admin:
class ContactAdmin(admin.ModelAdmin):
list_filter = (
AppCategory,
)
def queryset(self, request):
return super(ContactAdmin, self).queryset(request).prefetch_related(
'apps',
'to_contact',
)
# the main list_filter that is causing troubles:
class AppCategory(admin.SimpleListFilter):
title = 'app category'
parameter_name = 'app_category'
def lookups(self, request, modelAdmin):
return [
('Action', 'Action'),
('Adventure', 'Adventure'),
('Arcade', 'Arcade'),
('Board', 'Board'),
('Books', 'Books'),
('Books & Reference', 'Books & Reference'),
('Business', 'Business'),
('Card', 'Card'),
('Casino', 'Casino',),
('Casual', 'Casual'),
('Catalogs', 'Catalogs'),
('Comics', 'Comics'),
('Communication', 'Communication'),
('Education', 'Education'),
('Educational', 'Educational'),
('Entertainment', 'Entertainment'),
('Family', 'Family'),
('Finance', 'Finance'),
('Food & Drink', 'Food & Drink'),
('Games', 'Games'),
('Health & Fitness', 'Health & Fitness'),
('Libraries & Demo', 'Libraries & Demo'),
('Lifestyle', 'Lifestyle'),
('Media & Video', 'Media & Video'),
('Medical', 'Medical'),
('Music', 'Music'),
('Music & Audio', 'Music & Audio'),
('Navigation', 'Navigation'),
('News', 'News'),
('News & Magazines', 'News & Magazines'),
('Personalization', 'Personalization'),
('Photo & Video', 'Photo & Video'),
('Photography', 'Photography'),
('Productivity', 'Productivity'),
('Puzzle', 'Puzzle'),
('Racing', 'Racing'),
('Reference', 'Reference'),
('Role Playing', 'Role Playing'),
('Shopping', 'Shopping'),
('Simulation', 'Simulation'),
('Social', 'Social'),
('Social Networking', 'Social Networking'),
('Sports', 'Sports'),
('Strategy', 'Strategy'),
('Tools', 'Tools'),
('Transportation', 'Transportation'),
('Travel', 'Travel'),
('Travel & Local', 'Travel & Local'),
('Trivia', 'Trivia'),
('Utilities', 'Utilities'),
('Weather', 'Weather'),
('Word', 'Word')
]
def queryset(self, request, queryset):
if not self.value():
return queryset
else:
qs = queryset.filter(
apps__category=self.value()
)
return qs
我找到了答案。如果您过滤一个反向 ForeignKey
关系(在本例中为 apps__category
),一切正常。但我忘了说,我在 Django 管理页面的右侧组合了两个过滤器——另一个也是反向 ForeignKey
- apps__store
。当您这样做时,会执行两个完全相同的 INNER JOIN
,这会导致服务器超时。当我单独使用这些过滤器时,一切正常。