Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 查询太慢;与预回迁相关的未解决问题_Python_Django_Query Performance_Prefetch - Fatal编程技术网

Python 查询太慢;与预回迁相关的未解决问题

Python 查询太慢;与预回迁相关的未解决问题,python,django,query-performance,prefetch,Python,Django,Query Performance,Prefetch,我们将Django 2.1用于。我有每页显示96个用户的页面,对于每个用户,我想显示他在Speedy Match上有多少朋友,并且有一个活动的电子邮件地址。查询检查每个用户的(self.email\u addresses.filter(is\u confirm=True).exists())是否为True: def has_confirmed_email(self): return (self.email_addresses.filter(is_confirmed=True).exist

我们将Django 2.1用于。我有每页显示96个用户的页面,对于每个用户,我想显示他在Speedy Match上有多少朋友,并且有一个活动的电子邮件地址。查询检查每个用户的
(self.email\u addresses.filter(is\u confirm=True).exists())
是否为True:

def has_confirmed_email(self):
    return (self.email_addresses.filter(is_confirmed=True).exists())
对于96个用户中的每一个用户,它会检查他的所有朋友并运行此查询——每页超过数百次。获取用户的查询是
User.objects.all().order\u by()
,然后为每个用户检查此查询:

qs = self.friends.all().prefetch_related("from_user", "from_user__{}".format(SpeedyNetSiteProfile.RELATED_NAME), "from_user__{}".format(SpeedyMatchSiteProfile.RELATED_NAME), "from_user__email_addresses").distinct().order_by('-from_user__{}__last_visit'.format(SiteProfile.RELATED_NAME))
我在用户的管理器模型中添加了与预取相关的

def get_queryset(self):
    from speedy.net.accounts.models import SiteProfile as SpeedyNetSiteProfile
    from speedy.match.accounts.models import SiteProfile as SpeedyMatchSiteProfile
    return super().get_queryset().prefetch_related(SpeedyNetSiteProfile.RELATED_NAME, SpeedyMatchSiteProfile.RELATED_NAME, "email_addresses").distinct()
但是,将“电子邮件地址”和“来自用户的电子邮件地址”添加到与
预回迁相关的
并不能加快页面加载速度,加载页面大约需要16秒。当加载页面而不检查每个朋友是否有已确认的电子邮件地址时,加载页面大约需要3秒钟。是否有一种方法可以一次性加载用户的所有电子邮件地址,而不是每次检查用户时加载?事实上,我也希望朋友查询加载一次,而不是每页96次(每个用户一次),但页面加载时间为3秒钟,所以这并不重要。但是如果我能查询一下friends表,那会更好

查询是由以下行()引起的:

这由
is\u active\u和
调用,后者由
get\u matching\u rank
调用,以检查用户是否与特定用户匹配。这是通过模型中的方法
get\u friends
调用的

更新#1:如果我在模型中的
def已确认电子邮件(…)
中更改为
return True
,则页面加载速度仅快3秒(13秒而不是16秒),因此此页面中可能存在更多与性能相关的问题

如果我禁用
get\u matching\u rank
的功能,并将其替换为普通的
return 5
,页面加载速度会快得多。但是我们当然需要这个函数的功能。当为两个特定用户的集合调用此函数时,我们是否可以将其结果缓存几分钟

更新#2:我想在用户模型中添加一个布尔字段,如果用户有一个确认的电子邮件地址,则该字段将为真。该字段将在每次保存或删除电子邮件地址时更新。我知道如何覆盖save方法,但是当电子邮件地址被删除时,如何更新此字段?它也可能被管理员删除


我认为我应该使用诸如
post\u save
post\u delete
这样的信号,以便预回迁产生任何效果,您必须在用户模型上使用它-很难从您所包含的内容判断您是否在这样做

如果不为每个用户预取好友,则执行
self.friends.all()
将导致查询。要使用预回迁绕过查询,可以执行以下操作之一:

User.objects.prefetch_related('friends')
或者可以使用
预取
对象进一步筛选:

User.objects.prefetch_related(Prefetch(
    'friends',
    queryset=Friend.objects.filter(is_confirmed=True)
)
使用filter关键字参数的
Count
注释会快得多

from djang.db.models import Count, Q

qs = User.objects.annotate(
    friend_count=Count('friends', filter=Q(friends__is_confirmed=True)
)

要使预回迁产生任何效果,您必须在用户模型上使用它——很难从您所包含的内容判断您是否在这样做

如果不为每个用户预取好友,则执行
self.friends.all()
将导致查询。要使用预回迁绕过查询,可以执行以下操作之一:

User.objects.prefetch_related('friends')
或者可以使用
预取
对象进一步筛选:

User.objects.prefetch_related(Prefetch(
    'friends',
    queryset=Friend.objects.filter(is_confirmed=True)
)
使用filter关键字参数的
Count
注释会快得多

from djang.db.models import Count, Q

qs = User.objects.annotate(
    friend_count=Count('friends', filter=Q(friends__is_confirmed=True)
)

我在用户模型中添加了一个字段:

has_confirmed_email = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
    if ((self.is_staff) or (self.is_superuser)):
        warnings.warn('Can’t delete staff user.')
        return False
    else:
        self.email_addresses.all().delete() # This is necessary because of the signal above.
        return super().delete(*args, **kwargs)
方法是:

def _update_has_confirmed_email_field(self):
    self.has_confirmed_email = (self.email_addresses.filter(is_confirmed=True).count() > 0)
    self.save_user_and_profile()
以及:

在用户模型中:

has_confirmed_email = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
    if ((self.is_staff) or (self.is_superuser)):
        warnings.warn('Can’t delete staff user.')
        return False
    else:
        self.email_addresses.all().delete() # This is necessary because of the signal above.
        return super().delete(*args, **kwargs)

我还从管理员视图中删除了好友数,现在管理员视图页面在大约1.5秒内加载。

我在用户模型中添加了一个字段:

has_confirmed_email = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
    if ((self.is_staff) or (self.is_superuser)):
        warnings.warn('Can’t delete staff user.')
        return False
    else:
        self.email_addresses.all().delete() # This is necessary because of the signal above.
        return super().delete(*args, **kwargs)
方法是:

def _update_has_confirmed_email_field(self):
    self.has_confirmed_email = (self.email_addresses.filter(is_confirmed=True).count() > 0)
    self.save_user_and_profile()
以及:

在用户模型中:

has_confirmed_email = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
    if ((self.is_staff) or (self.is_superuser)):
        warnings.warn('Can’t delete staff user.')
        return False
    else:
        self.email_addresses.all().delete() # This is necessary because of the signal above.
        return super().delete(*args, **kwargs)
我还从管理员视图中删除了好友数,现在管理员视图页面的加载时间约为1.5秒

但是将“电子邮件地址”和“来自用户的电子邮件地址”添加到
预回迁相关的
并不能加快页面加载速度

这是因为
self.email\u addresses.filter(is\u confirm=True).exists()
不使用预取的
QuerySet

要使用预取的
self.email\u地址
,请在内存中进行筛选:

def已确认电子邮件(self):
如果self.email\u addresses.all().\u result\u缓存不是无:
返回任何(电子邮件地址。已确认self.email\u addresses.all()中的电子邮件地址)
return(self.email\u addresses.filter(is\u confirm=True).exists())
注意:如果没有预取,那么改进的实现仍然会在每个
已确认的\u电子邮件
函数调用中命中数据库,因为
.filter
仍然会创建一个新的
查询集
。为了处理这个问题,make
已经确认了一封电子邮件
一个Django
@cached\u属性

解释 发件人:

请记住,与
QuerySets
一样,任何暗示不同数据库查询的后续链接方法都将忽略以前缓存的结果,并使用新的数据库查询检索数据

>pizzas=Pizza.objects.prefetch\u相关('toppings'))
>>>[比萨饼中比萨饼的列表(pizza.toppings.filter(spice=True))
。。。预取缓存在这里无能为力;事实上,这会影响性能,因为您已经完成了一个尚未使用的数据库查询。因此,请谨慎使用此功能

但是将“电子邮件地址”和“来自用户的电子邮件地址”添加到
预回迁相关的
并不能加快页面加载速度

这是因为
self.email\u addresses.filter(is\u confirm=True).exists()
不使用预取的
QuerySet

使用预设置