如何在一个查询中获取多个内容的第一页结果

时间:2018-05-27 11:28:31

标签: django postgresql

这个问题有点难以解释,但我会尽我所能。我正在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

我不认为我需要案例陈述,因为我认为没有必要能够批准后续页面 - 只是初始页面。

所以我对此有几个问题:

  1. 有没有更好的方法来编写此查询?

  2. 这是否优先以并行方式触发多个(实际上在10到30之间)查询,以传统方式执行此操作?

  3. 如何使用Django ORM实现此查询(不降低到原始SQL)?

  4. 第三个问题是我正在敲打的问题,因为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)
    

0 个答案:

没有答案