Django 中的查询集优化
QuerySet Optimisations in Django
我只是想知道,我有以下两个伪相关的查询:
organisation = Organisation.objects.get(pk=org_id)
employees = Employee.objects.filter(organisation=organisation).filter(is_active=True)
每个 Employee
都与 Organisation
有 ForeignKey 关系。
我想知道在本机 Django ORM 的一个查询中是否可以利用任何东西来执行上述操作?
另外,会:
employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)
是一种更快的获取方式employees
?
Willem 的参考,employees
然后用作:
# Before constructing **parameters, it is neccessary to filter out any supurfluous key, value pair that do not correspond to model attributes:
if len(request.GET.getlist('gender[]')) > 0:
parameters['gender__in'] = request.GET.getlist('gender[]')
employees = employees.filter(**parameters)
if len(request.GET.getlist('age_group[]')) > 0:
parameters['age_group__in'] = request.GET.getlist('age_group[]')
employees = employees.filter(**parameters)
results = SurveyResult.objects.filter(
user__in=employees,
created_date__range=date_range,
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
我省略了这个,因为它似乎对我最初的目标来说是不必要的并发症。
Also, would:
employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)
Be a quicker way to fetch employees
?
不,或者可能是勉强,因为本质上这就是 Django ORM 自己做的事情:它会简单地获取 organisation
的主键,然后像您描述的那样进行查询。
如果不需要organisation
本身,可以查询:
employees = Employee.objects.filter(organisation_id=<b>org_pk</b>, is_active=True)
此外,例如,您可以在组织上执行 .select_related(..)
[Django-doc],以在与员工相同的查询中加载 organisation
的数据,尽管减少了一个额外的查询,通常并没有太大的区别。如果 iut 导致 N+1 个查询,则性能更成问题。
例如,我们可以 "piggyback" 通过获取员工来获取 Organisation
详细信息,例如:
employees = list(
Employee.objects.select_related('organization').filter(
organisation_id=org_pk, is_active=True
)
)
if employees: # at least one employee
organization = employees[0].organization
但是无论如何,如前所述,一两个查询之间的差异并不那么那么多。如果您有 N+1 个查询,这通常是一个更大的问题。有点可惜的是 Django/Python 似乎没有 Haxl [GitHub] 等价物,可以通过代数分析快速检索(远程)资源。
如果您对 Employee
servey 结果感兴趣,您可以查询:
results = SurveyResult.objects.filter(
<b>user__organization_id=org_pk,</b>
created_date__range=date_range,
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
因此,如果您不需要这些,您可以 省略 单独查询 Employee
。
您还可以将过滤器添加到您的查询中,例如:
<b>emp_filter = {}</b>
genders = request.GET.getlist('gender[]')
if genders:
emp_filter['user__gender__in'] = genders
age_groups = request.GET.getlist('age_group[]')
if age_groups:
emp_filter['user__age_group__in'] = age_groups
results = SurveyResult.objects.filter(
user__organization_id=org_pk,
created_date__range=date_range,
<b>**emp_filter</b>
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
如果您在组织和员工之间有外键关系,那么您可以像这样使用 select_related 获取员工:
employees = Employee.objects.selected_related('organisation').filter(is_active=True)
或
organisation = Organisation.objects.get(pk=org_id)
employees =organisation.employee_set.all() #your_employee_model_name_set.all
我只是想知道,我有以下两个伪相关的查询:
organisation = Organisation.objects.get(pk=org_id)
employees = Employee.objects.filter(organisation=organisation).filter(is_active=True)
每个 Employee
都与 Organisation
有 ForeignKey 关系。
我想知道在本机 Django ORM 的一个查询中是否可以利用任何东西来执行上述操作?
另外,会:
employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)
是一种更快的获取方式employees
?
Willem 的参考,employees
然后用作:
# Before constructing **parameters, it is neccessary to filter out any supurfluous key, value pair that do not correspond to model attributes:
if len(request.GET.getlist('gender[]')) > 0:
parameters['gender__in'] = request.GET.getlist('gender[]')
employees = employees.filter(**parameters)
if len(request.GET.getlist('age_group[]')) > 0:
parameters['age_group__in'] = request.GET.getlist('age_group[]')
employees = employees.filter(**parameters)
results = SurveyResult.objects.filter(
user__in=employees,
created_date__range=date_range,
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
我省略了这个,因为它似乎对我最初的目标来说是不必要的并发症。
Also, would:
employees = Employee.objects.filter(organisation__id=organisation.id).filter(is_active=True)
Be a quicker way to fetch
employees
?
不,或者可能是勉强,因为本质上这就是 Django ORM 自己做的事情:它会简单地获取 organisation
的主键,然后像您描述的那样进行查询。
如果不需要organisation
本身,可以查询:
employees = Employee.objects.filter(organisation_id=<b>org_pk</b>, is_active=True)
此外,例如,您可以在组织上执行 .select_related(..)
[Django-doc],以在与员工相同的查询中加载 organisation
的数据,尽管减少了一个额外的查询,通常并没有太大的区别。如果 iut 导致 N+1 个查询,则性能更成问题。
例如,我们可以 "piggyback" 通过获取员工来获取 Organisation
详细信息,例如:
employees = list(
Employee.objects.select_related('organization').filter(
organisation_id=org_pk, is_active=True
)
)
if employees: # at least one employee
organization = employees[0].organization
但是无论如何,如前所述,一两个查询之间的差异并不那么那么多。如果您有 N+1 个查询,这通常是一个更大的问题。有点可惜的是 Django/Python 似乎没有 Haxl [GitHub] 等价物,可以通过代数分析快速检索(远程)资源。
如果您对 Employee
servey 结果感兴趣,您可以查询:
results = SurveyResult.objects.filter(
<b>user__organization_id=org_pk,</b>
created_date__range=date_range,
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
因此,如果您不需要这些,您可以 省略 单独查询 Employee
。
您还可以将过滤器添加到您的查询中,例如:
<b>emp_filter = {}</b>
genders = request.GET.getlist('gender[]')
if genders:
emp_filter['user__gender__in'] = genders
age_groups = request.GET.getlist('age_group[]')
if age_groups:
emp_filter['user__age_group__in'] = age_groups
results = SurveyResult.objects.filter(
user__organization_id=org_pk,
created_date__range=date_range,
<b>**emp_filter</b>
).annotate(
date=TruncDate('created_date'),
).values(
'survey',
'date',
).annotate(
score=Sum('normalized_score'),
participants=Count('user'),
).order_by(
'survey',
'date',
)
如果您在组织和员工之间有外键关系,那么您可以像这样使用 select_related 获取员工:
employees = Employee.objects.selected_related('organisation').filter(is_active=True)
或
organisation = Organisation.objects.get(pk=org_id)
employees =organisation.employee_set.all() #your_employee_model_name_set.all