情况:
表 Waypoints 相对较大(150M 行)并且包含(除其他外)列 user_id 和时间戳 tracked_at。
表 Storyline 是一个较小的表(300K 行),其中包含有关时间片段(t_min 到 t_max,也可通过 tsrange segment_time 获得)、user_id 等信息。
目的:将segments表的信息添加到user_id匹配且timestamp在t_range内的points表中(有一个唯一匹配)。
EXPLAIN CREATE TABLE t4 AS SELECT
w.waypoint_id,
s.storyline_id
FROM waypoints w JOIN storyline s
ON w.tracked_at <@ s.segment_time and w.user_id = s.user_id;
问题:如何在此处使用索引来加快连接速度?
我认为这里有必要,根据这是故事情节上 (user_id, t_segment_time) 上的btree_gist索引,或者,如果我使用带有 t_min 和 t_max 而不是范围的查询,则在 (user_id, t_min, t_max DESC 上使用普通索引)。但是,我总是得到一个类似于以下的查询计划:
"Hash Join (cost=329264.29..8085010946.88 rows=553075874 width=16)"
" Hash Cond: (w.user_id = s.user_id)"
" Join Filter: (w.tracked_at <@ s.segment_time)"
" -> Seq Scan on waypoints w (cost=0.00..4503125.76 rows=152813376 width=24)"
" -> Hash (cost=323059.13..323059.13 rows=496413 width=38)"
" -> Seq Scan on storyline s (cost=0.00..323059.13 rows=496413 width=38)"
我理解航点上的顺序扫描(毕竟,我希望所有点都回来),但我觉得索引扫描而不是 Storyline 上的顺序扫描应该快得多。为什么顺序扫描在这里应该更快?如果没有,实现索引扫描需要哪些索引?
编辑: 按照 a_horse_with_no_name 的建议,这里是表的创建语句:
CREATE TABLE public.storyline
(
storyline_id bigint NOT NULL,
user_id bigint NOT NULL,
t_min timestamp without time zone NOT NULL,
t_max timestamp without time zone NOT NULL,
...
segment_time tsrange, -- as tsrange(t_min, t_max, '[)')
CONSTRAINT storyline_pkey PRIMARY KEY (storyline_id)
)
CREATE INDEX i_storyline_uid_t
ON public.storyline
USING btree
(user_id, t_min, t_max);
CREATE INDEX i_storyline_uid_t_2
ON public.storyline
USING btree
(user_id, t_min, t_max DESC);
CREATE INDEX i_storyline_uid_tseg
ON public.storyline
USING gist
(user_id, segment_time);
和航点:
CREATE TABLE public.waypoints
(
waypoint_id bigint NOT NULL,
user_id bigint,
tracked_at timestamp without time zone,
...
CONSTRAINT "none" PRIMARY KEY (waypoint_id)
)
CREATE INDEX i_waypoints_id
ON public.waypoints
USING btree
(waypoint_id);
CREATE INDEX i_waypoints_uid_t
ON public.waypoints
USING btree
(user_id, tracked_at);
Aso 解释分析:我很想这样做,但到目前为止,我在等待超过一天后失去了耐心。我假设如果大表的简单遍历持续 2-3 分钟,那么从一个小得多的其他表中添加唯一的对应项应该最多在几个小时内是可行的。但我可以让它运行更长时间,让你知道结果。