Vectorize filters with external parameters

For example, comparison to a query parameter in a parameterized prepared
query.
This commit is contained in:
Alexander Kuzmenkov 2024-01-11 11:50:02 +01:00
parent 662fcc1b1b
commit 1cd77b3a24
4 changed files with 130 additions and 42 deletions

View File

@ -373,15 +373,24 @@ is_not_runtime_constant_walker(Node *node, void *context)
{
case T_Var:
case T_PlaceHolderVar:
case T_Param:
/*
* We might want to support these nodes to have vectorizable
* join clauses (T_Var), join clauses referencing a variable that is
* above outer join (T_PlaceHolderVar) or initplan parameters and
* prepared statement parameters (T_Param). We don't support them at
* the moment.
* We might want to support these nodes to have vectorizable join
* clauses (T_Var) or join clauses referencing a variable that is
* above outer join (T_PlaceHolderVar). We don't suppor them at the
* moment.
*/
return true;
case T_Param:
/*
* We support external query parameters (e.g. from parameterized
* prepared statements), because they are constant for the duration
* of the query.
*
* Join and initplan parameters are passed as PARAM_EXEC and require
* support in the Rescan functions of the custom scan node. We don't
* support them at the moment.
*/
return castNode(Param, node)->paramkind != PARAM_EXTERN;
default:
if (check_functions_in_node(node,
contains_volatile_functions_checker,

View File

@ -132,7 +132,55 @@ select tag from vectorqual where metric2 > 0;
tag5
(5 rows)
-- Can't vectorize parameterized join clauses for now.
set timescaledb.debug_require_vector_qual to 'forbid';
set enable_hashjoin to off;
set enable_mergejoin to off;
with values(x) as materialized(select distinct metric2 from vectorqual)
select x, (select metric2 from vectorqual where metric2 = x) from values order by 1;
x | metric2
----+---------
12 | 12
22 | 22
32 | 32
42 | 42
52 | 52
(5 rows)
reset enable_hashjoin;
reset enable_mergejoin;
-- Can't vectorize initplan parameters either.
select count(*) from vectorqual where metric2
= (select metric2 from vectorqual order by 1 limit 1);
count
-------
1
(1 row)
-- Can vectorize clauses with query parameters.
set timescaledb.debug_require_vector_qual to 'only';
set plan_cache_mode to 'force_generic_plan';
prepare p as select count(*) from vectorqual where metric3 = $1;
execute p(33);
count
-------
1
(1 row)
deallocate p;
-- Also try query parameter in combination with a stable function.
create function stable_identity(x anyelement) returns anyelement as $$ select x $$ language sql stable;
prepare p(int4) as select count(*) from vectorqual where metric3 = stable_identity($1);
execute p(33);
count
-------
1
(1 row)
deallocate p;
reset plan_cache_mode;
-- Queries without aggregation.
set timescaledb.debug_require_vector_qual to 'only';
select * from vectorqual where ts > '2021-01-01 00:00:00' order by vectorqual;
ts | metric2 | device | metric3 | metric4 | tag
--------------------------+---------+--------+---------+---------+------

View File

@ -2124,17 +2124,17 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_compressed (actual rows=5 loops=1)
Chunks excluded during runtime: 2
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=5 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 4995
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=5 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 15
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(16 rows)
@ -2144,17 +2144,17 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_compressed (actual rows=5 loops=1)
Chunks excluded during runtime: 2
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=5 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 4995
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=5 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 25
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(16 rows)
@ -2164,15 +2164,15 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_compressed (actual rows=0 loops=1)
Chunks excluded during runtime: 3
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(14 rows)
@ -3407,45 +3407,45 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=5 loops=1)
Chunks excluded during runtime: 6
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 999
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 3
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=3 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 2997
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=3 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 9
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 999
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 3
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(44 rows)
@ -3455,45 +3455,45 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=5 loops=1)
Chunks excluded during runtime: 6
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 999
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 5
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=3 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 2997
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=3 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 15
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
Rows Removed by Filter: 999
-> Seq Scan on compress_hyper_X_X_chunk (actual rows=1 loops=1)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
Rows Removed by Filter: 5
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(44 rows)
@ -3503,39 +3503,39 @@ QUERY PLAN
Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=0 loops=1)
Chunks excluded during runtime: 9
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
-> Custom Scan (DecompressChunk) on _hyper_X_X_chunk (never executed)
Filter: ("time" = $1)
Vectorized Filter: ("time" = $1)
-> Seq Scan on compress_hyper_X_X_chunk (never executed)
Filter: ((_ts_meta_min_1 <= $1) AND (_ts_meta_max_1 >= $1))
(38 rows)

View File

@ -47,7 +47,38 @@ set timescaledb.debug_require_vector_qual to 'only';
select tag from vectorqual where metric2 > 0;
-- Can't vectorize parameterized join clauses for now.
set timescaledb.debug_require_vector_qual to 'forbid';
set enable_hashjoin to off;
set enable_mergejoin to off;
with values(x) as materialized(select distinct metric2 from vectorqual)
select x, (select metric2 from vectorqual where metric2 = x) from values order by 1;
reset enable_hashjoin;
reset enable_mergejoin;
-- Can't vectorize initplan parameters either.
select count(*) from vectorqual where metric2
= (select metric2 from vectorqual order by 1 limit 1);
-- Can vectorize clauses with query parameters.
set timescaledb.debug_require_vector_qual to 'only';
set plan_cache_mode to 'force_generic_plan';
prepare p as select count(*) from vectorqual where metric3 = $1;
execute p(33);
deallocate p;
-- Also try query parameter in combination with a stable function.
create function stable_identity(x anyelement) returns anyelement as $$ select x $$ language sql stable;
prepare p(int4) as select count(*) from vectorqual where metric3 = stable_identity($1);
execute p(33);
deallocate p;
reset plan_cache_mode;
-- Queries without aggregation.
set timescaledb.debug_require_vector_qual to 'only';
select * from vectorqual where ts > '2021-01-01 00:00:00' order by vectorqual;
select * from vectorqual where metric4 >= 0 order by vectorqual;