Skip runtime exclusion when Param is not partitioning column

When the column a Param references is not a partitioning column
the constraint is not useful for excluding chunks so we skip
enabling runtime exclusion for those cases.
This commit is contained in:
Sven Klemm 2019-06-22 04:00:18 -04:00 committed by Sven Klemm
parent 6f936ea2e3
commit 8c2acecbf4
7 changed files with 193 additions and 1 deletions

View File

@ -9,9 +9,11 @@
#include <optimizer/pathnode.h>
#include <optimizer/paths.h>
#include <optimizer/tlist.h>
#include <optimizer/var.h>
#include <utils/builtins.h>
#include <utils/typcache.h>
#include "hypertable.h"
#include "chunk_append/chunk_append.h"
#include "chunk_append/planner.h"
#include "compat.h"
@ -70,7 +72,30 @@ ts_chunk_append_path_create(PlannerInfo *root, RelOptInfo *rel, Hypertable *ht,
path->startup_exclusion = true;
if (ts_guc_enable_runtime_exclusion && contain_param_exec((Node *) rinfo->clause))
path->runtime_exclusion = true;
{
ListCell *lc_var;
/*
* check the param references a partitioning column of the hypertable
* otherwise we skip runtime exclusion
*/
foreach (lc_var, pull_var_clause((Node *) rinfo->clause, 0))
{
Var *var = lfirst(lc_var);
/*
* varattno 0 is whole row and varattno less than zero are
* system columns so we skip those even though
* ts_is_partitioning_column would return the correct
* answer for those as well
*/
if (var->varno == rel->relid && var->varattno > 0 &&
ts_is_partitioning_column(ht, var->varattno))
{
path->runtime_exclusion = true;
break;
}
}
}
}
/*

View File

@ -1872,3 +1872,16 @@ ts_hypertable_get_all_by_name(Name schema_name, Name table_name, MemoryContext m
return data.ht_oids;
}
bool
ts_is_partitioning_column(Hypertable *ht, Index column_attno)
{
uint16 i;
for (i = 0; i < ht->space->num_dimensions; i++)
{
if (column_attno == ht->space->dimensions[i].column_attno)
return true;
}
return false;
}

View File

@ -106,6 +106,7 @@ extern Tablespace *ts_hypertable_get_tablespace_at_offset_from(int32 hypertable_
extern bool ts_hypertable_has_tuples(Oid table_relid, LOCKMODE lockmode);
extern void ts_hypertables_rename_schema_name(const char *old_name, const char *new_name);
extern List *ts_hypertable_get_all_by_name(Name schema_name, Name table_name, MemoryContext mctx);
extern bool ts_is_partitioning_column(Hypertable *ht, Index column_attno);
#define hypertable_scan(schema, table, tuple_found, data, lockmode, tuplock) \
ts_hypertable_scan_with_memory_context(schema, \

View File

@ -1044,6 +1044,31 @@ ORDER BY time DESC;
Heap Fetches: 129
(31 rows)
-- test runtime exclusion does not activate for constraints on non-partitioning columns
-- should not use runtime exclusion
:PREFIX SELECT * FROM append_test a LEFT JOIN LATERAL(SELECT * FROM join_test j WHERE a.colorid = j.colorid ORDER BY time DESC LIMIT 1) j ON true ORDER BY a.time LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------
Limit (actual rows=1 loops=1)
-> Nested Loop Left Join (actual rows=1 loops=1)
-> Custom Scan (ChunkAppend) on append_test a (actual rows=1 loops=1)
Order: a."time"
-> Index Scan Backward using _hyper_1_1_chunk_append_test_time_idx on _hyper_1_1_chunk a_1 (actual rows=1 loops=1)
-> Index Scan Backward using _hyper_1_2_chunk_append_test_time_idx on _hyper_1_2_chunk a_2 (never executed)
-> Index Scan Backward using _hyper_1_3_chunk_append_test_time_idx on _hyper_1_3_chunk a_3 (never executed)
-> Limit (actual rows=1 loops=1)
-> Custom Scan (ChunkAppend) on join_test j (actual rows=1 loops=1)
Order: j."time" DESC
-> Index Scan using _hyper_2_6_chunk_join_test_time_idx on _hyper_2_6_chunk j_1 (actual rows=0 loops=1)
Filter: (a.colorid = colorid)
Rows Removed by Filter: 1
-> Index Scan using _hyper_2_5_chunk_join_test_time_idx on _hyper_2_5_chunk j_2 (actual rows=0 loops=1)
Filter: (a.colorid = colorid)
Rows Removed by Filter: 1
-> Index Scan using _hyper_2_4_chunk_join_test_time_idx on _hyper_2_4_chunk j_3 (actual rows=1 loops=1)
Filter: (a.colorid = colorid)
(18 rows)
-- test runtime exclusion with LATERAL and generate_series
:PREFIX SELECT g.time FROM generate_series('2000-01-01'::timestamptz, '2000-02-01'::timestamptz, '1d'::interval) g(time) LEFT JOIN LATERAL(SELECT time FROM metrics_timestamptz m WHERE m.time=g.time LIMIT 1) m ON true;
QUERY PLAN
@ -1117,6 +1142,33 @@ ORDER BY time DESC;
Heap Fetches: 6
(19 rows)
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time>g.time + '1 day' ORDER BY time LIMIT 1) m ON true;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (actual rows=30 loops=1)
-> Function Scan on generate_series g (actual rows=32 loops=1)
-> Limit (actual rows=1 loops=32)
-> Custom Scan (ChunkAppend) on metrics_timestamptz m (actual rows=1 loops=32)
Order: m."time"
Chunks excluded during startup: 0
Chunks excluded during runtime: 2
-> Index Only Scan Backward using _hyper_5_17_chunk_metrics_timestamptz_time_idx on _hyper_5_17_chunk m_1 (actual rows=1 loops=4)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 4
-> Index Only Scan Backward using _hyper_5_18_chunk_metrics_timestamptz_time_idx on _hyper_5_18_chunk m_2 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_19_chunk_metrics_timestamptz_time_idx on _hyper_5_19_chunk m_3 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_20_chunk_metrics_timestamptz_time_idx on _hyper_5_20_chunk m_4 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_21_chunk_metrics_timestamptz_time_idx on _hyper_5_21_chunk m_5 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 5
(22 rows)
-- test runtime exclusion with subquery
:PREFIX SELECT m1.time FROM metrics_timestamptz m1 WHERE m1.time=(SELECT max(time) FROM metrics_timestamptz);
QUERY PLAN

View File

@ -1044,6 +1044,31 @@ ORDER BY time DESC;
Heap Fetches: 129
(31 rows)
-- test runtime exclusion does not activate for constraints on non-partitioning columns
-- should not use runtime exclusion
:PREFIX SELECT * FROM append_test a LEFT JOIN LATERAL(SELECT * FROM join_test j WHERE a.colorid = j.colorid ORDER BY time DESC LIMIT 1) j ON true ORDER BY a.time LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------
Limit (actual rows=1 loops=1)
-> Nested Loop Left Join (actual rows=1 loops=1)
-> Custom Scan (ChunkAppend) on append_test a (actual rows=1 loops=1)
Order: a."time"
-> Index Scan Backward using _hyper_1_1_chunk_append_test_time_idx on _hyper_1_1_chunk a_1 (actual rows=1 loops=1)
-> Index Scan Backward using _hyper_1_2_chunk_append_test_time_idx on _hyper_1_2_chunk a_2 (never executed)
-> Index Scan Backward using _hyper_1_3_chunk_append_test_time_idx on _hyper_1_3_chunk a_3 (never executed)
-> Limit (actual rows=1 loops=1)
-> Custom Scan (ChunkAppend) on join_test j (actual rows=1 loops=1)
Order: j."time" DESC
-> Index Scan using _hyper_2_6_chunk_join_test_time_idx on _hyper_2_6_chunk j_1 (actual rows=0 loops=1)
Filter: (a.colorid = colorid)
Rows Removed by Filter: 1
-> Index Scan using _hyper_2_5_chunk_join_test_time_idx on _hyper_2_5_chunk j_2 (actual rows=0 loops=1)
Filter: (a.colorid = colorid)
Rows Removed by Filter: 1
-> Index Scan using _hyper_2_4_chunk_join_test_time_idx on _hyper_2_4_chunk j_3 (actual rows=1 loops=1)
Filter: (a.colorid = colorid)
(18 rows)
-- test runtime exclusion with LATERAL and generate_series
:PREFIX SELECT g.time FROM generate_series('2000-01-01'::timestamptz, '2000-02-01'::timestamptz, '1d'::interval) g(time) LEFT JOIN LATERAL(SELECT time FROM metrics_timestamptz m WHERE m.time=g.time LIMIT 1) m ON true;
QUERY PLAN
@ -1117,6 +1142,33 @@ ORDER BY time DESC;
Heap Fetches: 6
(19 rows)
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time>g.time + '1 day' ORDER BY time LIMIT 1) m ON true;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (actual rows=30 loops=1)
-> Function Scan on generate_series g (actual rows=32 loops=1)
-> Limit (actual rows=1 loops=32)
-> Custom Scan (ChunkAppend) on metrics_timestamptz m (actual rows=1 loops=32)
Order: m."time"
Chunks excluded during startup: 0
Chunks excluded during runtime: 2
-> Index Only Scan Backward using _hyper_5_17_chunk_metrics_timestamptz_time_idx on _hyper_5_17_chunk m_1 (actual rows=1 loops=4)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 4
-> Index Only Scan Backward using _hyper_5_18_chunk_metrics_timestamptz_time_idx on _hyper_5_18_chunk m_2 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_19_chunk_metrics_timestamptz_time_idx on _hyper_5_19_chunk m_3 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_20_chunk_metrics_timestamptz_time_idx on _hyper_5_20_chunk m_4 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 7
-> Index Only Scan Backward using _hyper_5_21_chunk_metrics_timestamptz_time_idx on _hyper_5_21_chunk m_5 (actual rows=1 loops=7)
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
Heap Fetches: 5
(22 rows)
-- test runtime exclusion with subquery
:PREFIX SELECT m1.time FROM metrics_timestamptz m1 WHERE m1.time=(SELECT max(time) FROM metrics_timestamptz);
QUERY PLAN

View File

@ -936,6 +936,29 @@ ORDER BY time DESC;
Index Cond: ("time" = m1."time")
(20 rows)
-- test runtime exclusion does not activate for constraints on non-partitioning columns
-- should not use runtime exclusion
:PREFIX SELECT * FROM append_test a LEFT JOIN LATERAL(SELECT * FROM join_test j WHERE a.colorid = j.colorid ORDER BY time DESC LIMIT 1) j ON true ORDER BY a.time LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
Limit
-> Nested Loop Left Join
-> Custom Scan (ChunkAppend) on append_test a
Order: a."time"
-> Index Scan Backward using _hyper_1_1_chunk_append_test_time_idx on _hyper_1_1_chunk a_1
-> Index Scan Backward using _hyper_1_2_chunk_append_test_time_idx on _hyper_1_2_chunk a_2
-> Index Scan Backward using _hyper_1_3_chunk_append_test_time_idx on _hyper_1_3_chunk a_3
-> Limit
-> Custom Scan (ChunkAppend) on join_test j
Order: j."time" DESC
-> Index Scan using _hyper_2_6_chunk_join_test_time_idx on _hyper_2_6_chunk j_1
Filter: (a.colorid = colorid)
-> Index Scan using _hyper_2_5_chunk_join_test_time_idx on _hyper_2_5_chunk j_2
Filter: (a.colorid = colorid)
-> Index Scan using _hyper_2_4_chunk_join_test_time_idx on _hyper_2_4_chunk j_3
Filter: (a.colorid = colorid)
(16 rows)
-- test runtime exclusion with LATERAL and generate_series
:PREFIX SELECT g.time FROM generate_series('2000-01-01'::timestamptz, '2000-02-01'::timestamptz, '1d'::interval) g(time) LEFT JOIN LATERAL(SELECT time FROM metrics_timestamptz m WHERE m.time=g.time LIMIT 1) m ON true;
QUERY PLAN
@ -991,6 +1014,27 @@ ORDER BY time DESC;
Index Cond: ("time" = g."time")
(13 rows)
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time>g.time + '1 day' ORDER BY time LIMIT 1) m ON true;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Nested Loop
-> Function Scan on generate_series g
-> Limit
-> Custom Scan (ChunkAppend) on metrics_timestamptz m
Order: m."time"
Chunks excluded during startup: 0
-> Index Only Scan Backward using _hyper_5_17_chunk_metrics_timestamptz_time_idx on _hyper_5_17_chunk m_1
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
-> Index Only Scan Backward using _hyper_5_18_chunk_metrics_timestamptz_time_idx on _hyper_5_18_chunk m_2
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
-> Index Only Scan Backward using _hyper_5_19_chunk_metrics_timestamptz_time_idx on _hyper_5_19_chunk m_3
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
-> Index Only Scan Backward using _hyper_5_20_chunk_metrics_timestamptz_time_idx on _hyper_5_20_chunk m_4
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
-> Index Only Scan Backward using _hyper_5_21_chunk_metrics_timestamptz_time_idx on _hyper_5_21_chunk m_5
Index Cond: ("time" > (g."time" + '@ 1 day'::interval))
(16 rows)
-- test runtime exclusion with subquery
:PREFIX SELECT m1.time FROM metrics_timestamptz m1 WHERE m1.time=(SELECT max(time) FROM metrics_timestamptz);
QUERY PLAN

View File

@ -218,10 +218,15 @@ ORDER BY time DESC;
-- test runtime exclusion with LATERAL and 2 hypertables
:PREFIX SELECT m1.time, m2.time FROM metrics_timestamptz m1 LEFT JOIN LATERAL(SELECT time FROM metrics_timestamptz m2 WHERE m1.time = m2.time LIMIT 1) m2 ON true ORDER BY m1.time;
-- test runtime exclusion does not activate for constraints on non-partitioning columns
-- should not use runtime exclusion
:PREFIX SELECT * FROM append_test a LEFT JOIN LATERAL(SELECT * FROM join_test j WHERE a.colorid = j.colorid ORDER BY time DESC LIMIT 1) j ON true ORDER BY a.time LIMIT 1;
-- test runtime exclusion with LATERAL and generate_series
:PREFIX SELECT g.time FROM generate_series('2000-01-01'::timestamptz, '2000-02-01'::timestamptz, '1d'::interval) g(time) LEFT JOIN LATERAL(SELECT time FROM metrics_timestamptz m WHERE m.time=g.time LIMIT 1) m ON true;
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time=g.time) m ON true;
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time=g.time ORDER BY time) m ON true;
:PREFIX SELECT * FROM generate_series('2000-01-01'::timestamptz,'2000-02-01'::timestamptz,'1d'::interval) AS g(time) INNER JOIN LATERAL (SELECT time FROM metrics_timestamptz m WHERE time>g.time + '1 day' ORDER BY time LIMIT 1) m ON true;
-- test runtime exclusion with subquery
:PREFIX SELECT m1.time FROM metrics_timestamptz m1 WHERE m1.time=(SELECT max(time) FROM metrics_timestamptz);