You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL单查询中Top-N与Last-N查询优化相关问题

1. LATERAL使用合理性判断

你的用法完全合理。
当前你只需要针对WHERE筛选出的1.9万条figure记录关联对应的step,LATERAL的执行逻辑是逐行匹配符合条件的figure,仅查询对应figure_id的step记录,完全避免了7000万行figure_step表的全量关联,比直接两次LEFT JOIN全表关联的执行效率高得多,和你的需求场景高度匹配。

2. 优化方案

2.1 基础优化(性价比最高)

先给figure_step创建联合覆盖索引:

CREATE INDEX idx_figure_step_status_num ON figure_step (figure_id, status, number);

该索引可以直接覆盖两个LATERAL子查询的过滤、排序、取值逻辑,不需要回表查询,单条子查询的耗时可以降到微秒级,这是当前场景下投入最小收益最大的优化手段,优化后原有SQL的性能已经足够优秀。

2.2 子查询复用方案

如果要避免两次查询figure_step,可以用窗口函数的方案,单次查询即可拿到两个目标step:

SELECT * FROM figure f
LEFT JOIN LATERAL (
    SELECT
        -- 按需提取DELAYED step的字段
        MAX(id) FILTER (WHERE status = 'DELAYED' AND rn_asc = 1) AS delayed_step_id,
        MAX(number) FILTER (WHERE status = 'DELAYED' AND rn_asc = 1) AS delayed_step_number,
        -- 按需提取FINISHED step的字段
        MAX(id) FILTER (WHERE status = 'FINISHED' AND rn_desc = 1) AS finished_step_id,
        MAX(number) FILTER (WHERE status = 'FINISHED' AND rn_desc = 1) AS finished_step_number
    FROM (
        SELECT 
            id, number, status,
            ROW_NUMBER() OVER (PARTITION BY status ORDER BY number ASC) AS rn_asc,
            ROW_NUMBER() OVER (PARTITION BY status ORDER BY number DESC) AS rn_desc
        FROM figure_step fs
        WHERE fs.figure_id = f.id
          AND fs.status IN ('DELAYED', 'FINISHED')
    ) t
    WHERE rn_asc = 1 OR rn_desc = 1
) fs ON TRUE
WHERE ...
LIMIT ... OFFSET ...

该方案仅针对每个符合条件的figure查询一次符合状态要求的step记录,通过窗口函数计算排序后直接取两个目标值,减少了一次索引查询,单figure对应step数量越多,收益越明显。

内容的提问来源于stack exchange,提问作者Vasya Rogov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 09:36:01