Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 37 additions & 78 deletions src/planner/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -1166,71 +1166,29 @@ rte_should_expand(const RangeTblEntry *rte)
}

static void
expand_hypertables(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte)
expand_hypertable(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte)
{
bool set_pathlist_for_current_rel = false;
Hypertable *ht;
double total_pages;
bool reenabled_inheritance = false;

for (int i = 1; i < root->simple_rel_array_size; i++)
{
RangeTblEntry *in_rte = root->simple_rte_array[i];

#if PG18_GE
/* RTE could be removed due to self-join
* elimination optimization.
*
* https://github.com/postgres/postgres/commit/5f6f95
*/
if (!in_rte)
{
continue;
}
#endif

if (rte_should_expand(in_rte) && root->simple_rel_array[i])
{
RelOptInfo *in_rel = root->simple_rel_array[i];
Hypertable *ht = ts_planner_get_hypertable(in_rte->relid, CACHE_FLAG_NOCREATE);

Assert(ht != NULL && in_rel != NULL);
ts_plan_expand_hypertable_chunks(ht, root, in_rel, in_rte->ctename != TS_FK_EXPAND);

in_rte->inh = true;
reenabled_inheritance = true;
/* Redo set_rel_consider_parallel, as results of the call may no longer be valid
* here (due to adding more tables to the set of tables under consideration here).
* This is especially true if dealing with foreign data wrappers. */
Assert(rte_should_expand(rte));
Assert(rti == rel->relid);

/*
* An entry of reloptkind RELOPT_OTHER_MEMBER_REL might still
* be a hypertable here if it was pulled up from a subquery
* as happens with UNION ALL for example.
*/
if (in_rel->reloptkind == RELOPT_BASEREL ||
in_rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
{
Assert(in_rte->relkind == RELKIND_RELATION);
ts_set_rel_size(root, in_rel, i, in_rte);
}
ht = ts_planner_get_hypertable(rte->relid, CACHE_FLAG_NOCREATE);
Assert(ht != NULL);
ts_plan_expand_hypertable_chunks(ht, root, rel, rte->ctename != TS_FK_EXPAND);

/* if we're activating inheritance during a hypertable's pathlist
* creation then we're past the point at which postgres will add
* paths for the children, and we have to do it ourselves. We delay
* the actual setting of the pathlists until after this loop,
* because set_append_rel_pathlist will eventually call this hook again.
*/
if (in_rte == rte)
{
Assert(rti == (Index) i);
set_pathlist_for_current_rel = true;
}
}
}
rte->inh = true;

if (!reenabled_inheritance)
/*
* An entry of reloptkind RELOPT_OTHER_MEMBER_REL might still
* be a hypertable here if it was pulled up from a subquery
* as happens with UNION ALL for example.
*/
if (rel->reloptkind == RELOPT_BASEREL || rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
{
return;
Assert(rte->relkind == RELKIND_RELATION);
ts_set_rel_size(root, rel, rti, rte);
}

total_pages = 0;
Expand All @@ -1257,13 +1215,14 @@ expand_hypertables(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry
}
root->total_table_pages = total_pages;

if (set_pathlist_for_current_rel)
{
rel->pathlist = NIL;
rel->partial_pathlist = NIL;

ts_set_append_rel_pathlist(root, rel, rti, rte);
}
/*
* We are past the point at which postgres will add paths for the children,
* so we have to do it ourselves. set_append_rel_pathlist will eventually
* call this hook again for each child chunk.
*/
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
ts_set_append_rel_pathlist(root, rel, rti, rte);
}

static void
Expand Down Expand Up @@ -1447,20 +1406,9 @@ timescaledb_set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, Rang
reltype = ts_classify_relation(root, rel, &ht);

/* Check for unexpanded hypertable */
if (!rte->inh && ts_rte_is_marked_for_expansion(rte))
{
expand_hypertables(root, rel, rti, rte);
}

if (ts_guc_enable_optimizations)
if (rte_should_expand(rte))
{
ts_planner_constraint_cleanup(root, rel);
}

/* Call other extensions. Do it after table expansion. */
if (prev_set_rel_pathlist_hook != NULL)
{
(*prev_set_rel_pathlist_hook)(root, rel, rti, rte);
expand_hypertable(root, rel, rti, rte);
}

switch (reltype)
Expand Down Expand Up @@ -1510,6 +1458,17 @@ timescaledb_set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, Rang
apply_optimizations(root, reltype, rel, rte, ht);
break;
}

if (ts_guc_enable_optimizations)
{
ts_planner_constraint_cleanup(root, rel);
}

/* Call other extensions. Do it after table expansion. */
if (prev_set_rel_pathlist_hook != NULL)
{
(*prev_set_rel_pathlist_hook)(root, rel, rti, rte);
}
}

/* This hook is meant to editorialize about the information the planner gets
Expand Down
2 changes: 1 addition & 1 deletion test/expected/append-16.out
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ DROP INDEX :INDEX_NAME;
Limit (actual rows=3.00 loops=1)
-> Merge Join (actual rows=3.00 loops=1)
Merge Cond: (m2."time" = m1."time")
Join Filter: (m1.device_id = m2.device_id)
Join Filter: (m2.device_id = m1.device_id)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caused by different equivalence member creation order, basically the reverse of changes in #9714.

Rows Removed by Join Filter: 4
-> Custom Scan (ChunkAppend) on join_limit m2 (actual rows=3.00 loops=1)
Order: m2."time", m2.device_id
Expand Down
2 changes: 1 addition & 1 deletion test/expected/append-17.out
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ DROP INDEX :INDEX_NAME;
Limit (actual rows=3.00 loops=1)
-> Merge Join (actual rows=3.00 loops=1)
Merge Cond: (m2."time" = m1."time")
Join Filter: (m1.device_id = m2.device_id)
Join Filter: (m2.device_id = m1.device_id)
Rows Removed by Join Filter: 4
-> Custom Scan (ChunkAppend) on join_limit m2 (actual rows=3.00 loops=1)
Order: m2."time", m2.device_id
Expand Down
2 changes: 1 addition & 1 deletion test/expected/append-18.out
Original file line number Diff line number Diff line change
Expand Up @@ -1746,7 +1746,7 @@ DROP INDEX :INDEX_NAME;
Limit (actual rows=3.00 loops=1)
-> Merge Join (actual rows=3.00 loops=1)
Merge Cond: (m2."time" = m1."time")
Join Filter: (m1.device_id = m2.device_id)
Join Filter: (m2.device_id = m1.device_id)
Rows Removed by Join Filter: 4
-> Custom Scan (ChunkAppend) on join_limit m2 (actual rows=3.00 loops=1)
Order: m2."time", m2.device_id
Expand Down
102 changes: 44 additions & 58 deletions test/expected/plan_expand_hypertable-16.out
Original file line number Diff line number Diff line change
Expand Up @@ -3013,52 +3013,45 @@ SELECT o2_m1.time FROM metrics_timestamptz o2_m1 FULL OUTER JOIN metrics_timesta
Hash Cond: (o2_m1."time" = o1_m1."time")
-> Nested Loop
-> Append
-> Index Scan Backward using _hyper_7_168_chunk_metrics_timestamptz_2_time_idx on _hyper_7_168_chunk o2_m2_1
Index Cond: ("time" > 'Thu Jan 20 00:00:00 2000 PST'::timestamp with time zone)
-> Seq Scan on _hyper_6_160_chunk o2_m1_1
Filter: (device_id = 2)
-> Seq Scan on _hyper_7_169_chunk o2_m2_2
-> Seq Scan on _hyper_6_161_chunk o2_m1_2
Filter: (device_id = 2)
-> Seq Scan on _hyper_7_170_chunk o2_m2_3
-> Seq Scan on _hyper_6_162_chunk o2_m1_3
Filter: (device_id = 2)
-> Append
-> Index Scan using _hyper_6_160_chunk_metrics_timestamptz_time_idx on _hyper_6_160_chunk o2_m1_1
Index Cond: ("time" = o2_m2."time")
-> Seq Scan on _hyper_6_163_chunk o2_m1_4
Filter: (device_id = 2)
-> Index Scan using _hyper_6_161_chunk_metrics_timestamptz_time_idx on _hyper_6_161_chunk o2_m1_2
Index Cond: ("time" = o2_m2."time")
-> Seq Scan on _hyper_6_164_chunk o2_m1_5
Filter: (device_id = 2)
-> Index Scan using _hyper_6_162_chunk_metrics_timestamptz_time_idx on _hyper_6_162_chunk o2_m1_3
Index Cond: ("time" = o2_m2."time")
-> Append
-> Index Scan using _hyper_7_168_chunk_metrics_timestamptz_2_time_idx on _hyper_7_168_chunk o2_m2_1
Index Cond: (("time" = o2_m1."time") AND ("time" > 'Thu Jan 20 00:00:00 2000 PST'::timestamp with time zone))
Filter: (device_id = 2)
-> Index Scan using _hyper_6_163_chunk_metrics_timestamptz_time_idx on _hyper_6_163_chunk o2_m1_4
Index Cond: ("time" = o2_m2."time")
-> Index Scan using _hyper_7_169_chunk_metrics_timestamptz_2_time_idx on _hyper_7_169_chunk o2_m2_2
Index Cond: ("time" = o2_m1."time")
Filter: (device_id = 2)
-> Index Scan using _hyper_6_164_chunk_metrics_timestamptz_time_idx on _hyper_6_164_chunk o2_m1_5
Index Cond: ("time" = o2_m2."time")
-> Index Scan using _hyper_7_170_chunk_metrics_timestamptz_2_time_idx on _hyper_7_170_chunk o2_m2_3
Index Cond: ("time" = o2_m1."time")
Filter: (device_id = 2)
-> Hash
-> Nested Loop
-> Append
-> Seq Scan on _hyper_7_165_chunk o1_m2_1
-> Seq Scan on _hyper_6_160_chunk o1_m1_1
Filter: (device_id = 1)
-> Index Scan Backward using _hyper_7_166_chunk_metrics_timestamptz_2_time_idx on _hyper_7_166_chunk o1_m2_2
Index Cond: ("time" < 'Mon Jan 10 00:00:00 2000 PST'::timestamp with time zone)
-> Seq Scan on _hyper_6_161_chunk o1_m1_2
Filter: (device_id = 1)
-> Append
-> Index Scan using _hyper_6_160_chunk_metrics_timestamptz_time_idx on _hyper_6_160_chunk o1_m1_1
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_162_chunk o1_m1_3
Filter: (device_id = 1)
-> Index Scan using _hyper_6_161_chunk_metrics_timestamptz_time_idx on _hyper_6_161_chunk o1_m1_2
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_163_chunk o1_m1_4
Filter: (device_id = 1)
-> Index Scan using _hyper_6_162_chunk_metrics_timestamptz_time_idx on _hyper_6_162_chunk o1_m1_3
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_164_chunk o1_m1_5
Filter: (device_id = 1)
-> Index Scan using _hyper_6_163_chunk_metrics_timestamptz_time_idx on _hyper_6_163_chunk o1_m1_4
Index Cond: ("time" = o1_m2."time")
-> Append
-> Index Scan using _hyper_7_165_chunk_metrics_timestamptz_2_time_idx on _hyper_7_165_chunk o1_m2_1
Index Cond: ("time" = o1_m1."time")
Filter: (device_id = 1)
-> Index Scan using _hyper_6_164_chunk_metrics_timestamptz_time_idx on _hyper_6_164_chunk o1_m1_5
Index Cond: ("time" = o1_m2."time")
-> Index Scan using _hyper_7_166_chunk_metrics_timestamptz_2_time_idx on _hyper_7_166_chunk o1_m2_2
Index Cond: (("time" = o1_m1."time") AND ("time" < 'Mon Jan 10 00:00:00 2000 PST'::timestamp with time zone))
Filter: (device_id = 1)

:PREFIX
Expand All @@ -3074,52 +3067,45 @@ SELECT o2_m1.time FROM metrics_timestamptz o2_m1 FULL OUTER JOIN metrics_timesta
Hash Cond: (o2_m1."time" = o1_m1."time")
-> Nested Loop
-> Append
-> Index Scan Backward using _hyper_7_168_chunk_metrics_timestamptz_2_time_idx on _hyper_7_168_chunk o2_m2_1
Index Cond: ("time" > 'Thu Jan 20 00:00:00 2000 PST'::timestamp with time zone)
-> Seq Scan on _hyper_6_160_chunk o2_m1_1
Filter: (device_id = 2)
-> Seq Scan on _hyper_7_169_chunk o2_m2_2
-> Seq Scan on _hyper_6_161_chunk o2_m1_2
Filter: (device_id = 2)
-> Seq Scan on _hyper_7_170_chunk o2_m2_3
-> Seq Scan on _hyper_6_162_chunk o2_m1_3
Filter: (device_id = 2)
-> Append
-> Index Scan using _hyper_6_160_chunk_metrics_timestamptz_time_idx on _hyper_6_160_chunk o2_m1_1
Index Cond: ("time" = o2_m2."time")
-> Seq Scan on _hyper_6_163_chunk o2_m1_4
Filter: (device_id = 2)
-> Index Scan using _hyper_6_161_chunk_metrics_timestamptz_time_idx on _hyper_6_161_chunk o2_m1_2
Index Cond: ("time" = o2_m2."time")
-> Seq Scan on _hyper_6_164_chunk o2_m1_5
Filter: (device_id = 2)
-> Index Scan using _hyper_6_162_chunk_metrics_timestamptz_time_idx on _hyper_6_162_chunk o2_m1_3
Index Cond: ("time" = o2_m2."time")
-> Append
-> Index Scan using _hyper_7_168_chunk_metrics_timestamptz_2_time_idx on _hyper_7_168_chunk o2_m2_1
Index Cond: (("time" = o2_m1."time") AND ("time" > 'Thu Jan 20 00:00:00 2000 PST'::timestamp with time zone))
Filter: (device_id = 2)
-> Index Scan using _hyper_6_163_chunk_metrics_timestamptz_time_idx on _hyper_6_163_chunk o2_m1_4
Index Cond: ("time" = o2_m2."time")
-> Index Scan using _hyper_7_169_chunk_metrics_timestamptz_2_time_idx on _hyper_7_169_chunk o2_m2_2
Index Cond: ("time" = o2_m1."time")
Filter: (device_id = 2)
-> Index Scan using _hyper_6_164_chunk_metrics_timestamptz_time_idx on _hyper_6_164_chunk o2_m1_5
Index Cond: ("time" = o2_m2."time")
-> Index Scan using _hyper_7_170_chunk_metrics_timestamptz_2_time_idx on _hyper_7_170_chunk o2_m2_3
Index Cond: ("time" = o2_m1."time")
Filter: (device_id = 2)
-> Hash
-> Nested Loop
-> Append
-> Seq Scan on _hyper_7_165_chunk o1_m2_1
-> Seq Scan on _hyper_6_160_chunk o1_m1_1
Filter: (device_id = 1)
-> Index Scan Backward using _hyper_7_166_chunk_metrics_timestamptz_2_time_idx on _hyper_7_166_chunk o1_m2_2
Index Cond: ("time" < 'Mon Jan 10 00:00:00 2000 PST'::timestamp with time zone)
-> Seq Scan on _hyper_6_161_chunk o1_m1_2
Filter: (device_id = 1)
-> Append
-> Index Scan using _hyper_6_160_chunk_metrics_timestamptz_time_idx on _hyper_6_160_chunk o1_m1_1
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_162_chunk o1_m1_3
Filter: (device_id = 1)
-> Index Scan using _hyper_6_161_chunk_metrics_timestamptz_time_idx on _hyper_6_161_chunk o1_m1_2
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_163_chunk o1_m1_4
Filter: (device_id = 1)
-> Index Scan using _hyper_6_162_chunk_metrics_timestamptz_time_idx on _hyper_6_162_chunk o1_m1_3
Index Cond: ("time" = o1_m2."time")
-> Seq Scan on _hyper_6_164_chunk o1_m1_5
Filter: (device_id = 1)
-> Index Scan using _hyper_6_163_chunk_metrics_timestamptz_time_idx on _hyper_6_163_chunk o1_m1_4
Index Cond: ("time" = o1_m2."time")
-> Append
-> Index Scan using _hyper_7_165_chunk_metrics_timestamptz_2_time_idx on _hyper_7_165_chunk o1_m2_1
Index Cond: ("time" = o1_m1."time")
Filter: (device_id = 1)
-> Index Scan using _hyper_6_164_chunk_metrics_timestamptz_time_idx on _hyper_6_164_chunk o1_m1_5
Index Cond: ("time" = o1_m2."time")
-> Index Scan using _hyper_7_166_chunk_metrics_timestamptz_2_time_idx on _hyper_7_166_chunk o1_m2_2
Index Cond: (("time" = o1_m1."time") AND ("time" < 'Mon Jan 10 00:00:00 2000 PST'::timestamp with time zone))
Filter: (device_id = 1)

\set ECHO errors
Expand Down
Loading
Loading