PostgREST 在子查询或 CTE 中使用限制和偏移量
Posted
技术标签:
【中文标题】PostgREST 在子查询或 CTE 中使用限制和偏移量【英文标题】:PostgREST using limit and offset in subqueries or CTE 【发布时间】:2018-05-29 21:35:48 【问题描述】:我们在项目中使用 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
B. CTE:
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
A 的问题是子选择是针对每一行执行的,所以即使我只读取了 1000 条记录,也有 100 000 个子选择。
B 的问题是与parts_count 表的连接需要很长时间,因为那里有100 0000 条记录(尽管with 查询只需要200 毫秒!对于2000 条记录)。理想情况下,我希望使用与主查询相同的限制和偏移量来限制parts_count 表,但我不能在 PostgREST 中执行此操作,因为它只是在末尾附加限制和偏移量,我无权访问里面的那些参数WITH 查询
【问题讨论】:
【参考方案1】:高OFFSET
不可避免地会导致性能不佳。
没有其他方法可以计算OFFSET
,只能扫描并丢弃所有行,直到达到偏移量,如果OFFSET
很高,世界上没有数据库会很快。
这是一个概念问题,避免它的唯一方法是避免OFFSET
。
如果您的目标是分页,那么通常keyset pagination 是更好的解决方案:
您添加一个符合您要求的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;
很奇怪,你没有ORDER BY
,而是LIMIT
和OFFSET
。这没有多大意义。
【讨论】:
这里主查询的偏移不是什么大问题,造成性能损失的是子查询。我做了一个测试,我使用了一个与主查询具有相同偏移量的 CTE,然后将它与主查询连接起来,性能可以接受。所以我试图在子选择中拦截外部查询的分页。类似于此处接受的答案***.com/questions/29307991/… 好的。如果您需要更多信息,则必须为您的问题添加更多详细信息。 我已经用更多细节更新了原始问题 我在答案中添加了改进的查询。 这只是我的查询的简化版本,我有一个原始的订单。我有点怀疑它是否会起作用,因为就像我说 PostgREST 只是在查询末尾添加limit
和 offset
但我明天会尝试并告诉你它是如何工作的。以上是关于PostgREST 在子查询或 CTE 中使用限制和偏移量的主要内容,如果未能解决你的问题,请参考以下文章
GREENPLUM中的with,即CTE用法,转自gp中文网文档