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

PostgreSQL嵌套/关联查询优化:获取匹配的最大oid_src值

PostgreSQL查询优化求助:获取关联记录的最大oid_src值

表结构

CREATE TABLE mytable (
    tm BIGINT NOT NULL,
    oid_src BIGINT NOT NULL,
    rel SMALLINT NOT NULL,
    oid_dst BIGINT NOT NULL,
    CONSTRAINT PK_Src_Rel_Dst PRIMARY KEY(oid_src, rel, oid_dst)
);
CREATE INDEX IX_TM ON mytable (tm DESC);

查询需求

筛选满足以下条件的记录,并获取匹配记录中oid_src的最大值:

  • oid_src = 1且rel为116或99
  • 存在至少一条同oid_dst、同rel的记录,其oid_src属于集合:{100488, 100489, 100490, 100491, 100492, 100493, 100494, 100495, 100496, 100497, 100498, 100499}

各阶段查询及性能分析

1. 初始COUNT子查询(耗时2.7ms)

SELECT te.tm, te.oid_src, te.rel, te.oid_dst
FROM mytable te
WHERE te.oid_src = 1 AND te.rel IN (116, 99)
AND (SELECT COUNT(*) FROM mytable te2
     WHERE te2.oid_src IN (100488, 100489, 100490, 100491, 100492, 100493, 100494,
                100495, 100496, 100497, 100498, 100499) 
       AND te2.oid_dst=te.oid_dst AND te2.rel=te.rel
   ) > 0
ORDER BY te.tm DESC
LIMIT 20;

2. EXISTS子查询(耗时2.2ms,无法获取最大oid_src)

性能更优,但无法返回需求中的最大oid_src值:

SELECT te.tm, te.oid_src, te.rel, te.oid_dst
FROM "mytable" te
WHERE te.oid_src = 1 AND te.rel IN (116, 99)
AND Exists (SELECT 1 FROM  "mytable" te2 WHERE te2.oid_src IN (100488, 100489, 100490, 100491, 100492, 100493, 100494, 100495, 100496, 100497, 100498, 100499)
AND te2.oid_dst=te.oid_dst AND te2.rel=te.rel)
ORDER BY te.tm DESC
LIMIT 20;

对应的EXPLAIN ANALYZE结果:

Limit  (cost=0.84..56.60 rows=20 width=26) (actual time=0.120..2.175 rows=20 loops=1)
  ->  Nested Loop Semi Join  (cost=0.84..12921.50 rows=4634 width=26) (actual time=0.120..2.174 rows=20 loops=1)
        ->  Index Scan using ix_tm on "mytable" te  (cost=0.42..10555.40 rows=4634 width=26) (actual time=0.027..0.931 rows=109 loops=1)
              Filter: ((rel = ANY ('{116,99}'::integer[])) AND (oid_src = 1))
              Rows Removed by Filter: 4471
        ->  Index Only Scan using pk_src_rel_dst on "mytable" te2  (cost=0.42..6.29 rows=1 width=10) (actual time=0.011..0.011 rows=0 loops=109)
              Index Cond: ((oid_src = ANY ('{100488,100489,100490,100491,100492,100493,100494,100495,100496,100497,100498,100499}'::bigint[])) AND (rel = te.rel) AND (oid_dst = te.oid_dst))
              Heap Fetches: 4
Planning Time: 0.271 ms
Execution Time: 2.192 ms

3. 满足需求但性能较差的查询(耗时约30ms)

能返回最大oid_src,但性能下降明显:

SELECT te.tm, max(te2.oid_src), te.rel, te.oid_dst
FROM mytable te, mytable te2
WHERE te.oid_src = 1 AND te.rel IN (116, 99) 
  AND te2.oid_src IN (100488, 100489, 100490, 100491, 100492, 100493, 100494,
                100495, 100496, 100497, 100498, 100499) 
  AND te2.oid_dst=te.oid_dst AND te2.rel=te.rel
GROUP BY te.tm, te.oid_src, te.rel, te.oid_dst
ORDER BY te.tm DESC
LIMIT 20;

对应的EXPLAIN ANALYZE结果:

Limit  (cost=8106.18..8106.23 rows=20 width=34) (actual time=28.779..28.784 rows=20 loops=1)
  ->  Sort  (cost=8106.18..8116.54 rows=4147 width=34) (actual time=28.778..28.781 rows=20 loops=1)
        Sort Key: te.tm DESC
        Sort Method: top-N heapsort  Memory: 27kB
        ->  HashAggregate  (cost=7954.36..7995.83 rows=4147 width=34) (actual time=23.854..26.601 rows=18910 loops=1)
              Group Key: te.rel, te.oid_dst
              Batches: 1  Memory Usage: 2577kB
              ->  Hash Join  (cost=1674.78..3477.46 rows=596920 width=34) (actual time=7.229..16.944 rows=29449 loops=1)
                    Hash Cond: ((te2.oid_dst = te.oid_dst) AND (te2.rel = te.rel))
                    ->  Index Only Scan using pk_src_rel_dst on mytable te2  (cost=0.42..1647.90 rows=29199 width=18) (actual time=0.010..3.558 rows=29499 loops=1)
                          Index Cond: (oid_src = ANY ('{100488,100489,100490,100491,100492,100493,100494,100495,100496,100497,100498,100499}'::bigint[]))
                          Heap Fetches: 2393
                    ->  Hash  (cost=1604.85..1604.85 rows=4634 width=26) (actual time=7.181..7.182 rows=21099 loops=1)
                          Buckets: 32768 (originally 8192)  Batches: 1 (originally 1)  Memory Usage: 1575kB
                          ->  Bitmap Heap Scan on mytable te  (cost=168.34..1604.85 rows=4634 width=26) (actual time=1.008..4.177 rows=21099 loops=1)
                                Recheck Cond: ((oid_src = 1) AND (rel = ANY ('{116,99}'::integer[])))
                                Heap Blocks: exact=467
                                ->  Bitmap Index Scan on pk_src_rel_dst  (cost=0.00..167.18 rows=4634 width=0) (actual time=0.966..0.966 rows=21099 loops=1)
                                      Index Cond: ((oid_src = 1) AND (rel = ANY ('{116,99}'::integer[])))
Planning Time: 0.311 ms
Execution Time: 29.347 ms

4. 优化后的CTE查询(耗时约3ms)

已修正原SQL中的语法错误(添加FROM关键字),性能接近EXISTS子查询且满足需求:

WITH wanted AS (
    SELECT tew.tm, tew.oid_dst, tew.rel FROM mytable tew
    WHERE tew.oid_src=1 AND tew.rel IN (116, 99)
)
SELECT w.tm, MAX(te.oid_src), te.rel, te.oid_dst FROM mytable te
 INNER JOIN wanted w ON w.oid_dst=te.oid_dst AND w.rel=te.rel
 WHERE te.oid_src IN (100488, 100489, 100490, 100491, 100492, 100493, 100494, 100495, 100496, 100497, 100498, 100499) AND te.rel IN (116, 99)
 GROUP BY w.tm, te.oid_dst, te.rel
 ORDER BY w.tm DESC
 LIMIT 20;

对应的EXPLAIN ANALYZE结果:

Limit  (cost=9.91..15.74 rows=20 width=26) (actual time=2.433..2.807 rows=20 loops=1)
  ->  GroupAggregate  (cost=9.91..46041.22 rows=157903 width=26) (actual time=2.432..2.805 rows=20 loops=1)
        Group Key: tew.tm, te.oid_dst, te.rel
        ->  Incremental Sort  (cost=9.91..42883.16 rows=157903 width=26) (actual time=2.429..2.793 rows=37 loops=1)
              Sort Key: tew.tm DESC, te.oid_dst, te.rel
              Presorted Key: tew.tm
              Full-sort Groups: 2  Sort Method: quicksort  Average Memory: 26kB  Peak Memory: 26kB
              ->  Nested Loop  (cost=0.85..36767.75 rows=157903 width=26) (actual time=0.122..2.775 rows=65 loops=1)
                    ->  Index Scan using ix_tm on mytable tew  (cost=0.42..10555.40 rows=4634 width=18) (actual time=0.022..0.976 rows=129 loops=1)
                          Filter: ((rel = ANY ('{116,99}'::integer[])) AND (oid_src = 1))
                          Rows Removed by Filter: 4589
                    ->  Memoize  (cost=0.43..6.30 rows=1 width=18) (actual time=0.011..0.014 rows=1 loops=129)
                          Cache Key: tew.oid_dst, tew.rel
                          Cache Mode: logical
                          Hits: 0  Misses: 129  Evictions: 0  Overflows: 0  Memory Usage: 13kB
                          ->  Index Only Scan using pk_src_rel_dst on "mytable" te  (cost=0.42..6.29 rows=1 width=18) (actual time=0.010..0.013 rows=1 loops=129)
                                Index Cond: ((oid_src = ANY ('{100488,100489,100490,100491,100492,100493,100494,100495,100496,100497,100498,100499}'::bigint[])) AND (rel = tew.rel) AND (oid_dst = tew.oid_dst))
                                Filter: (rel = ANY ('{116,99}'::integer[]))
                                Heap Fetches: 8
Planning Time: 0.363 ms
Execution Time: 2.951 ms

求助

目前已实现耗时约3ms的CTE查询,寻求进一步的优化建议或潜在问题排查方向。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:33:12