将视图加入 PostgreSQL 中的快速子查询/CTE 时性能非常糟糕

问题描述 投票:0回答:1

我有一个 PostgreSQL (v15) 数据库视图,它汇总单个组织的每个用户的大量数据,以显示数据报告,例如每个用户所欠/支付的费用等。这是使用组织 ID 和日期范围执行的作为输入,并执行亚秒级的操作,这对于此用例(UI 报告)来说非常快。到目前为止一切顺利。

对于某些组织,我还需要生成这些摘要的摘要,即组织的“组”的汇总,其中汇总了父组织的每个用户、每个组织的相同数据。高层,我试图首先选择目标组织(这应该产生一组 虽然真正的查询在输出中处理更多的列和聚合,但这个简化版本总结了核心查询逻辑:< 150 rows), then join my existing single-org view to that set to add in the aggregated data from the original view, but per collected organization.

WITH member_orgs AS ( -- CTE returns 133 rows in ~30ms SELECT bp.id AS billing_period_id, bp.started_on AS billing_period_started_on, bp.ended_on AS billing_period_ended_on, org.name AS organization_name, bp.organization_id FROM billing_periods bp JOIN organizations org ON org.id = bp.organization_id WHERE bp.paid_by_organization_id = 123 AND ( bp.started_on >= '2023-07-01' AND bp.ended_on <= '2024-06-30' ) AND bp.organization_id != 123 ) SELECT member_orgs.billing_period_id, member_orgs.billing_period_started_on, member_orgs.billing_period_ended_on, member_orgs.organization_name, -- this is one example aggregation, the real query has more of these: SUM(CASE WHEN details.received_amount > 0 THEN 1 ELSE 0 END) AS payments_received_count FROM member_orgs LEFT JOIN per_athlete_fee_details_view details -- SLOW (~40 SECONDS): -- ON details.billing_period_id = member_orgs.billing_period_id -- AND details.organization_id = member_orgs.organization_id -- FAST (~150ms): ON details.billing_period_id = 1234 AND details.organization_id = 3456 GROUP BY member_orgs.billing_period_id, member_orgs.billing_period_started_on, member_orgs.billing_period_ended_on, member_orgs.organization_name;

要连接的视图相当复杂,并且还依赖于一些子视图,但单独执行时速度非常快。 
member_orgs

CTE 本身也非常快(约 30 毫秒),并且总是在

内产生结果。< 150 records. As shown above, if I join the two on specific IDs (as a test), the overall query is extremely fast (~150ms). However, when joining on the columns between the CTE and the view (what I need to do), overall performance tanks to 40+ 我觉得我一定错过了一些愚蠢的事情,因为我不明白将视图连接到一组 133 条记录(在我正在调试的实际情况下)如何会如此戏剧性地增加时间。我的理解是,CTE 将具体化其输出,允许外部联接仅处理该结果集,我认为这是非常有效的。我可以编写应用程序代码来运行 CTE,然后迭代 ID 并单独执行外部查询 133 次,所需时间远少于此查询所花费的时间。

请原谅庞大的查询计划,因为真正的查询(带有底层视图)非常复杂,但这些查询是使用上面所示的简化查询示例的稍微复杂的版本创建的(尽管其逻辑是相同的)。两次运行之间的唯一区别是使用特定的 ID,而不是在列上连接,完全如上面的示例代码所示。

    快速版本
  • (通过特定ID)-在44ms内执行
  • 慢速版本
  • (加入 ID 列)- 在 41 秒以上执行
  • 提前致谢,如果我可以提供任何其他详细信息,请告诉我。

postgresql query-optimization sql-execution-plan postgresql-performance
1个回答
0
投票

© www.soinside.com 2019 - 2024. All rights reserved.