简体   繁体   English

最有效的 Django 查询以获取对象及其相关

[英]Most efficient Django query to get the objects and their related

I have this model:我有这个 model:

class Institution(models.Model):
    name = models.CharField(max_length=128, db_index=True)
    aliases = models.ManyToManyField('self', blank=True)

I would like to make the most efficient query that return all Institution where name contains the search term AND their aliases Institution .我想做最有效的查询,返回所有Institution ,其中name包含搜索词及其aliases Institution I came with the solution below that work but I was wondering if there's a simpler/more efficient way to achieve this?我在该工作下方提供了解决方案,但我想知道是否有更简单/更有效的方法来实现这一目标?

base_query = Institution.objects.filter(name__icontains='term')
pk_query = Q(pk__in=base_query)
aliases_query = Q(aliases__in=base_query)
final_query = Institution.objects.filter(pk_query|aliases_query).distinct()

Here is the SQL of this query:这是此查询的 SQL:

SELECT DISTINCT `app_institution`.`id`, `app_institution`.`name`
FROM `app_institution` LEFT OUTER JOIN `app_institution_aliases`
ON (`app_institution`.`id` = `app_institution_aliases`.`from_institution_id`)
WHERE (`app_institution`.`id`
IN (SELECT U0.`id` FROM `app_institution` U0 WHERE U0.`name` LIKE %term% )
OR `app_institution_aliases`.`to_institution_id`
IN (SELECT U0.`id` FROM `app_institution` U0 WHERE U0.`name` LIKE %term% ))
ORDER BY `app_institution`.`name` ASC LIMIT 21

UPDATE更新

By looking at the 2 first answers I got, I think I should specify more clearly what I want as results.通过查看我得到的第一个答案,我认为我应该更清楚地指定我想要的结果。

I want the UNION of我想要联合

  • the results of the base_query ( Institution where name contains the search term) base_query的结果( name包含搜索词的Institution

WITH

  • aliases of each of the Institution return by the base_query (theses aliases ' name don't need to contains the search term).每个Institutionaliasesbase_query返回(这些aliasesname不需要包含搜索词)。

Done in an inefficient (but easily understandable) way will be like that:以低效(但易于理解)的方式完成将是这样的:

base_query = Institution.objects.filter(name__icontains='term')
results= set(base_query)
for institution in base_query:
    results.update(institution.aliases.all())

2nd UPDATE第二次更新

Thinking about S.Lott answer, I finally figure out a way to do it with two queries that I join together after.考虑到 S.Lott 的答案,我终于找到了一种方法来处理我之后加入的两个查询。

base_query = Institution.objects.filter(name__icontains='term')
results= set(base_query)
aliases_query = Institution.objects.filter(aliases__in=base_query)
results.update(aliases_query)

I did some small benchmarks and this solution take around half time of the one with the one big query.我做了一些小的基准测试,这个解决方案大约需要一个大查询的一半时间。

But something that I forgot to take into account is the impact on the ordering...但是我忘记考虑的是对订购的影响......

Union queries -- like this -- are difficult.像这样的联合查询很困难。

It's important to review the use cases to be sure you really need to conflate two separate collections (by name and by alias) like this.查看用例以确保您确实需要像这样将两个单独的 collections(按名称和别名)混为一谈,这一点很重要。 Sometimes the web page can be presented with two collections, removing the need for a union.有时 web 页面可以显示两个 collections,从而无需联合。

Using Q objects to build "or" conditions is one way to create a union.使用Q对象构建“或”条件是创建联合的一种方法。

Assembling a separate collection from the two queries is another solution.从这两个查询中组装一个单独的集合是另一种解决方案。

name_query = Institution.objects.filter(name__icontains='term')
aliases_query = Institution.objects.filter(aliases__name__icontains='term')
final_query = list(name_query) + list(aliases_query)

The only way to know which is better is to benchmark the alternatives.知道哪个更好的唯一方法是对替代品进行基准测试。 The "complexity" of the SQL query text doesn't really mean much, because there are so many optimization steps inside an RDBMS. SQL 查询文本的“复杂性”实际上并没有多大意义,因为 RDBMS 中有很多优化步骤。

this:这个:

Institution.objects.filter(name__icontains='term', aliases__name__icontains='terms')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM