PostgREST 在子查询或 CTE 中使用限制和偏移量

cip*_*123 5 postgresql postgrest

我们在项目中使用 PostgREST 来处理一些相当复杂的数据库视图。

从某个时刻开始,当我们在子选择中使用限制和偏移(x 范围标头或查询参数)时,我们会得到非常长的响应时间。

从我们所读到的内容来看,这似乎是一个已知问题,postgresql 即使对于未请求的记录也会执行子选择。解决方案是稍微调整偏移量和限制,将其放入子选择或 CTE 表中。

是否有内部 GUC 值或类似的值可以在数据库视图中使用以优化响应时间?有人提示如何实现这一目标吗?

编辑:正如这里所建议的,有一些更多细节。假设产品和零件之间存在关系。我想知道每个产品的零件数量(这是我们公开的数据库视图的简化版本)。

有两种方法可以做到这一点

A. 子选择:

    SELECT products.id
            ,(
                    SELECT count(part_id) AS total
                    FROM parts
                    WHERE product_id = products.id
                    )
    FROM products limit 1000 OFFSET 99000
Run Code Online (Sandbox Code Playgroud)

B、热膨胀系数:

    WITH parts_count
    AS (
            SELECT product_id
                    ,count(part_id) AS total
            FROM parts
            GROUP BY product_id
            ORDER BY product_id
            )
    SELECT products.id
            ,parts_count.total
    FROM products
    LEFT JOIN parts_count ON parts_count.product_id = product.id 
    LIMIT 1000     
    OFFSET 99000
Run Code Online (Sandbox Code Playgroud)

A的问题是对每一行执行子选择,因此即使我只读取 1000 条记录,也有 100 000 个子选择。

B的问题是与 parts_count 表的连接需要很长时间,因为那里有 100 0000 条记录(尽管 with 查询对于 2000 条记录只需要 200 毫秒!)。理想情况下,我想使用与主查询相同的限制和偏移量来限制 parts_count 表,但我不能在 PostgREST 中执行此操作,因为它只是在末尾附加限制和偏移量,我无权访问内部的这些参数带查询

Lau*_*lbe 4

OFFSET高导致性能差是不可避免的。

没有其他方法可以计算,只能扫描并丢弃所有行,直到达到偏移量,如果偏移量很高,OFFSET世界上没有数据库会很快。OFFSET

这是一个概念问题,避免它的唯一方法就是避免OFFSET.

如果您的目标是分页,那么通常键集分页是更好的解决方案:

您添加ORDER BY符合您要求的子句,确保该ORDER BY子句中有唯一键并记住您找到的最后一个值。要获取下一页,请添加WHERE包含该值的条件。通过适当的索引支持,这可以非常快。

对于您的查询,更有效的版本可能是:

SELECT p.id
       count(parts.part_id) AS total
FROM (SELECT id FROM products
      LIMIT 1000 OFFSET 99000) p
   LEFT JOIN parts ON parts.product_id = p.id
GROUP BY p.id;
Run Code Online (Sandbox Code Playgroud)

很奇怪的是你没有ORDER BY, butLIMITOFFSET。这没有多大意义。