这个问题有点难以解释,但我会尽我所能。我正在Django中构建一个GraphQL服务器(使用Graphene),其中一部分是需要批量处理数据库查询以避免n + 1问题。这意味着,在提取一组事件时,不是每个事件ID进行一次查询,而是使用where id in (...)
进行单个查询。
我正在努力实现与列表相同的功能。我的直接用例是每个事件都有一个Venue,我想在一个查询中为每个Venue检索接下来的5个(这是任意的)事件。
(注意:对于这背后的完整理由,I wrote an article a while ago)
我提出的PostgreSQL查询是:
SELECT
*
FROM (
SELECT
*,
ROW_NUMBER()
OVER (PARTITION BY
venue_id
ORDER BY
starts_at,
ends_at,
id) AS row_index
FROM
events_event
WHERE
starts_at >= '2018-05-20') x
WHERE
row_index <= 5
我不认为我需要案例陈述,因为我认为没有必要能够批准后续页面 - 只是初始页面。
所以我对此有几个问题:
有没有更好的方法来编写此查询?
这是否优先以并行方式触发多个(实际上在10到30之间)查询,以传统方式执行此操作?
如何使用Django ORM实现此查询(不降低到原始SQL)?
第三个问题是我正在敲打的问题,因为ORM似乎提供了所有必要的构建块(我正在使用Django 2.0),但我无法弄清楚如何将它们粘在一起。
这是我到目前为止使用Django:
Event.objects.annotate(
row_number=Window(
expression=RowNumber(),
partition_by=[F('venue_id')],
order_by=[F('starts_at').asc(), F('ends_at').asc(), F('id').asc()]
)
)
但我一直无法找到一种方法来过滤row_number,因为我不想返回所有内容 - 只是第一个5.当我尝试以下内容时,Django告诉我不允许过滤窗口条款:
Event.objects.annotate(
row_number=Window(
expression=RowNumber(),
partition_by=[F('venue_id')],
order_by=[F('starts_at').asc(), F('ends_at').asc(), F('id').asc()]
)
).filter(row_number__lte=5)