Postgres:如何使用时间间隔在 timestamptz 上设置索引?
Postgres: How to setup an index on timestamptz using a time interval?
我有一个查询需要使用索引进行优化。有什么方法可以索引 timestamptz 类型的列 assigned_at 。我正在考虑使用 assigned_at 的 GIST 索引,有没有什么方法可以合并,因为我必须使用 now() 或传入可变且无法索引的当前日期时间。
select id from foo f where
f.context_id =
and (f.assigned_at <= (now() - interval '60 second') or f.assigned_at is null)
打开以获取为此查询设置索引的建议!提前致谢!!
考虑到您发布的查询,使用 context_id
和 assigned_at
的复合索引应该可以解决问题:
CREATE INDEX idx_foo ON foo (context_id,assigned_at);
根据您的数据,OR
条件可能会稍微减慢您的查询速度。另一种方法是将此条件拆分为两个不同的查询:
SELECT * FROM foo f
WHERE f.context_id = 1 AND f.assigned_at <= (now() - interval '60 second')
UNION ALL
SELECT * FROM foo f WHERE f.context_id = 1 AND f.assigned_at IS NULL;
一如既往,尝试两种查询并测试哪种方法最适合您的数据。
演示:db<>fiddle
(context_id, assigned_at)
上的简单 btree 索引可用于该查询。但是要充分利用所有部分,需要读取索引两次并在它们之间做一个 BitmapOr。根据它认为每个术语的选择性,它可能会选择采用不同的方法,例如仅对 context_id 使用索引并将时间部分用作过滤器。
explain analyze select id from foo f where
f.context_id = 7
and (f.assigned_at <= (now() - interval '60 second') or f.assigned_at is null);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo f (cost=8.88..12.90 rows=1 width=4) (actual time=0.031..0.041 rows=7 loops=1)
Recheck Cond: (((context_id = 7) AND (assigned_at <= (now() - '00:01:00'::interval))) OR ((context_id = 7) AND (assigned_at IS NULL)))
Filter: ((assigned_at <= (now() - '00:01:00'::interval)) OR (assigned_at IS NULL))
Heap Blocks: exact=4
-> BitmapOr (cost=8.88..8.88 rows=1 width=0) (actual time=0.024..0.025 rows=0 loops=1)
-> Bitmap Index Scan on foo_context_id_assigned_at_idx (cost=0.00..4.44 rows=1 width=0) (actual time=0.016..0.016 rows=0 loops=1)
Index Cond: ((context_id = 7) AND (assigned_at <= (now() - '00:01:00'::interval)))
-> Bitmap Index Scan on foo_context_id_assigned_at_idx (cost=0.00..4.43 rows=1 width=0) (actual time=0.007..0.007 rows=7 loops=1)
Index Cond: ((context_id = 7) AND (assigned_at IS NULL))
我有一个查询需要使用索引进行优化。有什么方法可以索引 timestamptz 类型的列 assigned_at 。我正在考虑使用 assigned_at 的 GIST 索引,有没有什么方法可以合并,因为我必须使用 now() 或传入可变且无法索引的当前日期时间。
select id from foo f where
f.context_id =
and (f.assigned_at <= (now() - interval '60 second') or f.assigned_at is null)
打开以获取为此查询设置索引的建议!提前致谢!!
考虑到您发布的查询,使用 context_id
和 assigned_at
的复合索引应该可以解决问题:
CREATE INDEX idx_foo ON foo (context_id,assigned_at);
根据您的数据,OR
条件可能会稍微减慢您的查询速度。另一种方法是将此条件拆分为两个不同的查询:
SELECT * FROM foo f
WHERE f.context_id = 1 AND f.assigned_at <= (now() - interval '60 second')
UNION ALL
SELECT * FROM foo f WHERE f.context_id = 1 AND f.assigned_at IS NULL;
一如既往,尝试两种查询并测试哪种方法最适合您的数据。
演示:db<>fiddle
(context_id, assigned_at)
上的简单 btree 索引可用于该查询。但是要充分利用所有部分,需要读取索引两次并在它们之间做一个 BitmapOr。根据它认为每个术语的选择性,它可能会选择采用不同的方法,例如仅对 context_id 使用索引并将时间部分用作过滤器。
explain analyze select id from foo f where
f.context_id = 7
and (f.assigned_at <= (now() - interval '60 second') or f.assigned_at is null);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo f (cost=8.88..12.90 rows=1 width=4) (actual time=0.031..0.041 rows=7 loops=1)
Recheck Cond: (((context_id = 7) AND (assigned_at <= (now() - '00:01:00'::interval))) OR ((context_id = 7) AND (assigned_at IS NULL)))
Filter: ((assigned_at <= (now() - '00:01:00'::interval)) OR (assigned_at IS NULL))
Heap Blocks: exact=4
-> BitmapOr (cost=8.88..8.88 rows=1 width=0) (actual time=0.024..0.025 rows=0 loops=1)
-> Bitmap Index Scan on foo_context_id_assigned_at_idx (cost=0.00..4.44 rows=1 width=0) (actual time=0.016..0.016 rows=0 loops=1)
Index Cond: ((context_id = 7) AND (assigned_at <= (now() - '00:01:00'::interval)))
-> Bitmap Index Scan on foo_context_id_assigned_at_idx (cost=0.00..4.43 rows=1 width=0) (actual time=0.007..0.007 rows=7 loops=1)
Index Cond: ((context_id = 7) AND (assigned_at IS NULL))