我有一个具有列playground
的表val
,对列val
进行了索引。
我有一个范围列表[(min1, max1), (min2, max2), ... , (minN, maxN)]
并且我想选择val
的所有行都适合任何这些范围。
例如我的范围如下所示:[(1,5), (20,25), (200,400)]
这是提取相应行的简单查询:
select p.*
from playground p
where (val between 1 AND 5) or (val between 20 and 25) or
(val between 200 and 400);
这里的问题是,该范围列表是动态的,我的应用程序生成了该列表并将其与查询一起发送到postgres。
我试图重写查询以接受动态范围列表:
select p.*
from playground p,
unnest(ARRAY [(1, 5),(20, 25),(200, 400)]) as r(min_val INT, max_val INT)
where p.val between r.min_val and r.max_val;
它提取相同的行,但我不知道这是一个有效的方法吗?
这是第一个查询的说明:
Bitmap Heap Scan on playground p (cost=12.43..16.45 rows=1 width=36) (actual time=0.017..0.018 rows=4 loops=1)
Recheck Cond: (((val >= 1) AND (val <= 5)) OR ((val >= 20) AND (val <= 25)) OR ((val >= 200) AND (val <= 400)))
Heap Blocks: exact=1
-> BitmapOr (cost=12.43..12.43 rows=1 width=0) (actual time=0.012..0.012 rows=0 loops=1)
-> Bitmap Index Scan on playground_val_index (cost=0.00..4.14 rows=1 width=0) (actual time=0.010..0.010 rows=3 loops=1)
Index Cond: ((val >= 1) AND (val <= 5))
-> Bitmap Index Scan on playground_val_index (cost=0.00..4.14 rows=1 width=0) (actual time=0.001..0.001 rows=0 loops=1)
Index Cond: ((val >= 20) AND (val <= 25))
-> Bitmap Index Scan on playground_val_index (cost=0.00..4.14 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
Index Cond: ((val >= 200) AND (val <= 400))
Planning Time: 0.071 ms
Execution Time: 0.057 ms
这是第二个的解释:
Nested Loop (cost=0.14..12.52 rows=2 width=36) (actual time=0.033..0.065 rows=4 loops=1)
-> Function Scan on unnest r (cost=0.00..0.03 rows=3 width=8) (actual time=0.011..0.012 rows=3 loops=1)
-> Index Scan using playground_val_index on playground p (cost=0.13..4.15 rows=1 width=36) (actual time=0.008..0.015 rows=1 loops=3)
Index Cond: ((val >= r.min_val) AND (val <= r.max_val))
Planning Time: 0.148 ms
Execution Time: 0.714 ms
注意:在两种情况下,我都set enable_seqscan = false;
使索引起作用。
我担心“嵌套循环”阶段。可以吗还是有更有效的方法将范围的动态列表传递到查询中?我的postgres版本是12.1
您添加了更多信息,但是还有更多相关信息。精确的表和索引定义,基数,数据分布,行大小统计信息,谓词的范围数,表的用途,写入模式等...性能优化需要它可以获得的所有输入。