我有这个型号:
class Institution(models.Model):
name = models.CharField(max_length=128, db_index=True)
aliases = models.ManyToManyField('self', blank=True)
我想提出最有效的查询,返回Institution
name
包含搜索字词及其aliases
Institution
的所有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()
。我带来了下面那个工作的解决方案,但我想知道是否有更简单/更有效的方法来实现这个目标?
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
以下是此查询的SQL:
base_query
通过查看我得到的第一个答案,我想我应该更清楚地说明我想要的结果。
我想要
的UNIONInstitution
(name
aliases
包含搜索字词的结果)使用
Institution
(base_query
'aliases
返回的每个name
的base_query = Institution.objects.filter(name__icontains='term')
results= set(base_query)
for institution in base_query:
results.update(institution.aliases.all())
不需要包含搜索字词。< / LI>
以低效(但易于理解)的方式完成:
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)
考虑到S.Lott的回答,我终于找到了一种方法来处理我之后加入的两个查询。
{{1}}
我做了一些小基准测试,这个解决方案占用了一个大问题的一半时间。
但我忘记考虑的是对订购的影响......
答案 0 :(得分:0)
联盟查询 - 就像这样 - 很难。
重要的是要检查用例,以确保真的需要将两个单独的集合(按名称和别名)混为一谈。有时,网页可以显示两个集合,无需联合。
使用Q
个对象构建“或”条件是创建联合的一种方法。
从两个查询中组合一个单独的集合是另一种解决方案。
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)
了解哪个更好的唯一方法是对替代方案进行基准测试。 SQL查询文本的“复杂性”并没有多大意义,因为RDBMS中有很多优化步骤。
答案 1 :(得分:0)
这样:
Institution.objects.filter(name__icontains='term', aliases__name__icontains='terms')