您的解决方案只能通过values('pk') 而不是values_list('id', flat=True) 稍微简化,因为这只会影响输出的一种类型,但是两个查询集的源 SQL 是相同的:
SELECT id FROM a WHERE val=42 UNION SELECT id FROM b WHERE val=42
而.count() 方法只对子查询进行查询:
SELECT COUNT(*) FROM (... subquery ...)
数据库后端不必将所有值保存在内存中。它也只能数数而忘记。 (未检查)
同样,如果你运行一个简单的SELECT COUNT(id) FROM a,它不需要收集id。
SELECT count(*) FROM a WHERE val=42 形式的子查询在更大的查询中是不可能的,因为 Django 不对聚合使用惰性求值并立即求值。
评估可以推迟,例如通过按一些只有一个可能值的表达式进行分组,例如GROUP BY (i >= 0)(如果可行,也可以通过外部引用),但查询计划可能更糟。
另一个问题是SELECT 在没有表格的情况下是不可能的。因此,我将在查询的基础上使用不重要表的不重要行。
例子:
qs = Unimportant.objects.filter(pk=unimportant_pk).values('id').annotate(
total_a=a.objects.filter(val=42).order_by().values('val')
.annotate(cnt=models.Count('*')).values('cnt'),
total_b=b.objects.filter(val=42).order_by().values('val')
.annotate(cnt=models.Count('*')).values('cnt')
)
这不是很好,但可以很容易地并行化
SELECT
id,
(SELECT COUNT(*) AS cnt FROM a WHERE val=42 GROUP BY val) AS total_a,
(SELECT COUNT(*) AS cnt FROM b WHERE val=42 GROUP BY val) AS total_b
FROM unimportant WHERE id = unimportant_pk
Django 文档确认不存在简单的解决方案。
Using aggregates within a Subquery expression
...
...这是在子查询中执行聚合的唯一方法,因为使用 aggregate() 尝试评估查询集(如果存在 OuterRef,则无法解决)。