情况:
表Waypoints相对较大(150M行),包含(其中包括)user_id列和时间戳tracked_at。
表格故事情节是一个较小的表格(300K行),其中包含有关时间剧集(t_min到t_max,也可通过tsrange segment_time提供),user_id等信息。
目标:将segments表的信息添加到user_id匹配的points表中,timestamp在t_range中(有一个唯一匹配)。
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;
问题:如何在此处使用索引来加速加入?
根据this,我在这里需要的是在故事情节上的(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)"
我理解航路点上的顺序扫描(毕竟,我希望所有点都回来),但我觉得索引扫描而不是故事情节上的顺序扫描要快得多。有没有理由为什么顺序扫描应该更快?如果没有,那么实现索引扫描需要哪些索引?
修改 根据a_horse_with_no_name的建议,以下是表的create语句:
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);
麻生太郎解释说:我很乐意这样做,但到目前为止,我等了一天以后就失去了耐心。我假设如果大表的简单遍历持续2-3分钟,那么从一个小得多的其他表中添加独特的对应物最多只能在几个小时内完成。 但我可以让它运行更长时间并让你知道结果。