Support intervals with day component when constifying now()

The initial patch to use now() expressions during planner hypertable
expansion only supported intervals with no day or month component.
This patch adds support for intervals with day component.

If the interval has a day component then the calculation needs
to take into account daylight saving time switches and thereby a
day would not always be exactly 24 hours. We mitigate this by
adding a safety buffer to account for these dst switches when
dealing with intervals with day component. These calculations
will be repeated with exact values during execution.
Since dst switches seem to range between -1 and 2 hours we set
the safety buffer to 4 hours.

This patch also refactors the tests since the previous tests
made it hard to tell the feature was working after the constified
values have been removed from the plans.
This commit is contained in:
Sven Klemm 2022-05-26 13:34:40 +02:00 committed by Sven Klemm
parent a6b5f9002c
commit 12574dc8ec
6 changed files with 1091 additions and 1324 deletions

View File

@ -6,6 +6,10 @@ accidentally triggering the load of a previous DB version.**
## Unreleased
**Features**
* #4374 Remove constified now() constraints from plan
* #4393 Support intervals with day component when constifying now()
## 2.7.0 (2022-05-24)
This release adds major new features since the 2.6.1 release.

View File

@ -33,9 +33,8 @@
* - Var >= now() - Interval
* - Var >= now() + Interval
*
* Additionally Interval needs to be Const and not contain day or month
* components as those would be affected by timezone, which can change
* between executions of a prepared statement.
* Additionally Interval needs to be Const and not contain a month
* component.
*/
static const Dimension *
get_hypertable_dimension(Oid relid)
@ -96,11 +95,11 @@ is_valid_now_expr(OpExpr *op, List *rtable)
Interval *offset = DatumGetIntervalP(c->constvalue);
/*
* We don't consider day or month intervals safe here as
* We don't consider month intervals safe here as
* they are affected by timezones and therefore not
* safe to evaluate during planning.
*/
if (offset->day != 0 || offset->month != 0)
if (offset->month != 0)
return false;
return true;
@ -145,6 +144,9 @@ constify_now_expr(PlannerInfo *root, OpExpr *op)
else
{
OpExpr *op_inner = lsecond_node(OpExpr, op->args);
Const *const_offset = lsecond_node(Const, op_inner->args);
Assert(const_offset->consttype == INTERVALOID);
Interval *offset = DatumGetIntervalP(const_offset->constvalue);
/*
* Sanity check that this is a supported expression. We should never
* end here if it isn't since this is checked in is_valid_now_expr.
@ -152,6 +154,24 @@ constify_now_expr(PlannerInfo *root, OpExpr *op)
Assert(linitial_node(FuncExpr, op_inner->args)->funcid == F_NOW);
linitial(op_inner->args) = make_now_const();
/*
* If the interval has a day component then the calculation needs
* to take into account daylight saving time switches and thereby a
* day would not always be exactly 24 hours. We mitigate this by
* adding a safety buffer to account for these dst switches when
* dealing with intervals with day component. These calculations
* will be repeated with exact values during execution.
* Since dst switches seem to range between -1 and 2 hours we set
* the safety buffer to 4 hours.
*/
if (offset->day != 0)
{
Const *now = linitial_node(Const, op_inner->args);
int64 now_value = DatumGetInt64(now->constvalue);
now_value -= 4 * USECS_PER_HOUR;
now->constvalue = Int64GetDatum(now_value);
}
/*
* Normally estimate_expression_value is not safe to use during planning
* since it also evaluates stable expressions. Since we only allow a

View File

@ -5,448 +5,309 @@ SET timescaledb.enable_chunk_append TO false;
SET timescaledb.enable_constraint_aware_append TO false;
SET timescaledb.current_timestamp_mock TO '1990-01-01';
\set PREFIX 'EXPLAIN (COSTS OFF, SUMMARY OFF, TIMING OFF)'
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '24h'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(7 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
(13 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Append
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(10 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(7 rows)
-- variants we don't optimize
-- we do not allow interval with day or month components
:PREFIX SELECT FROM metrics WHERE time > now() - '1d'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1week'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(7 rows)
:PREFIX SELECT FROM metrics WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
(10 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM metrics WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(22 rows)
:PREFIX SELECT FROM metrics WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
(22 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM metrics WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX WITH q1 AS (
SELECT * FROM metrics
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
-- JOIN
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Seq Scan on _hyper_X_X_chunk m1_2
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
(16 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
(16 rows)
-- test UPDATE
:PREFIX UPDATE metrics SET v0 = 0.1, v1 = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Update on metrics
Update on metrics
Update on _hyper_X_X_chunk
Update on _hyper_X_X_chunk
Update on _hyper_X_X_chunk
-> Seq Scan on metrics
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(13 rows)
-- test DELETE
:PREFIX DELETE FROM metrics WHERE time > now();
QUERY PLAN
Delete on metrics
Delete on metrics
Delete on _hyper_X_X_chunk
Delete on _hyper_X_X_chunk
Delete on _hyper_X_X_chunk
-> Seq Scan on metrics
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(13 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
CREATE TABLE const_now(time timestamptz, time2 timestamptz, value float);
-- does not apply to non-hypertables
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Seq Scan on const_now
Filter: ("time" > now())
(2 rows)
-- create a test table
-- any query with successful now_constify will have 1 chunk while
-- others will have 2 chunks in plan
CREATE TABLE const_now(time timestamptz, time2 timestamptz, device_id int, value float);
SELECT table_name FROM create_hypertable('const_now','time');
NOTICE: adding not-null constraint to column "time"
table_name
const_now
(1 row)
INSERT INTO const_now SELECT '2000-01-01','2000-01-01',0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',1,0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',2,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',1,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5;
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 2 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 3 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(2 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > now())
(4 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: (device_id = 2)
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(2 rows)
-- variants we don't optimize
-- we do not allow interval with month components
:PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(5 rows)
:PREFIX SELECT FROM const_now WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(5 rows)
:PREFIX SELECT FROM const_now WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
(7 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM const_now WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(15 rows)
:PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
(5 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM const_now WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX WITH q1 AS (
SELECT * FROM const_now
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(5 rows)
-- JOIN
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(6 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
(10 rows)
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(9 rows)
-- test UPDATE
:PREFIX UPDATE const_now SET value = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Update on const_now
Update on const_now
Update on _hyper_X_X_chunk
-> Seq Scan on const_now
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
-- test DELETE
:PREFIX DELETE FROM const_now WHERE time > now();
QUERY PLAN
Delete on const_now
Delete on const_now
Delete on _hyper_X_X_chunk
-> Seq Scan on const_now
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should have one time filter false
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- no constification because it's not partitioning column
:PREFIX SELECT FROM const_now WHERE time2 > now();
QUERY PLAN
Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(2 rows)
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(5 rows)
DROP TABLE const_now;
-- test prepared statements
@ -507,3 +368,48 @@ QUERY PLAN
-> Seq Scan on _hyper_X_X_chunk m3
(8 rows)
-- test dst interaction with day intervals
SET timezone TO 'Europe/Berlin';
CREATE TABLE const_now_dst(time timestamptz not null);
SELECT table_name FROM create_hypertable('const_now_dst','time',chunk_time_interval:='30minutes'::interval);
table_name
const_now_dst
(1 row)
-- create 2 chunks
INSERT INTO const_now_dst SELECT '2022-03-27 03:15:00+02';
INSERT INTO const_now_dst SELECT '2022-03-27 03:45:00+02';
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 0:45+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:45:00 2022 CEST
(1 row)
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 1:15+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:15:00 2022 CEST
Sun Mar 27 03:45:00 2022 CEST
(2 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
DROP TABLE const_now_dst;

View File

@ -5,448 +5,309 @@ SET timescaledb.enable_chunk_append TO false;
SET timescaledb.enable_constraint_aware_append TO false;
SET timescaledb.current_timestamp_mock TO '1990-01-01';
\set PREFIX 'EXPLAIN (COSTS OFF, SUMMARY OFF, TIMING OFF)'
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '24h'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(7 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
(13 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Append
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(10 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(7 rows)
-- variants we don't optimize
-- we do not allow interval with day or month components
:PREFIX SELECT FROM metrics WHERE time > now() - '1d'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1week'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(7 rows)
:PREFIX SELECT FROM metrics WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
(10 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM metrics WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(22 rows)
:PREFIX SELECT FROM metrics WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
(22 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM metrics WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX WITH q1 AS (
SELECT * FROM metrics
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
-- JOIN
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Seq Scan on _hyper_X_X_chunk m2_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Seq Scan on _hyper_X_X_chunk m1_2
-> Seq Scan on _hyper_X_X_chunk m1_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(16 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Seq Scan on _hyper_X_X_chunk m2_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(16 rows)
-- test UPDATE
:PREFIX UPDATE metrics SET v0 = 0.1, v1 = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Update on metrics
Update on metrics
Update on _hyper_X_X_chunk metrics_1
Update on _hyper_X_X_chunk metrics_2
Update on _hyper_X_X_chunk metrics_3
-> Seq Scan on metrics
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_1
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_2
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_3
Index Cond: ("time" > now())
(13 rows)
-- test DELETE
:PREFIX DELETE FROM metrics WHERE time > now();
QUERY PLAN
Delete on metrics
Delete on metrics
Delete on _hyper_X_X_chunk metrics_1
Delete on _hyper_X_X_chunk metrics_2
Delete on _hyper_X_X_chunk metrics_3
-> Seq Scan on metrics
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_1
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_2
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_3
Index Cond: ("time" > now())
(13 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
CREATE TABLE const_now(time timestamptz, time2 timestamptz, value float);
-- does not apply to non-hypertables
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Seq Scan on const_now
Filter: ("time" > now())
(2 rows)
-- create a test table
-- any query with successful now_constify will have 1 chunk while
-- others will have 2 chunks in plan
CREATE TABLE const_now(time timestamptz, time2 timestamptz, device_id int, value float);
SELECT table_name FROM create_hypertable('const_now','time');
NOTICE: adding not-null constraint to column "time"
table_name
const_now
(1 row)
INSERT INTO const_now SELECT '2000-01-01','2000-01-01',0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',1,0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',2,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',1,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5;
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 2 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 3 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(2 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > now())
(4 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: (device_id = 2)
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(2 rows)
-- variants we don't optimize
-- we do not allow interval with month components
:PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(5 rows)
:PREFIX SELECT FROM const_now WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(5 rows)
:PREFIX SELECT FROM const_now WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(date_part('epoch'::text, now())) > '0.5'::double precision)
-> Seq Scan on _hyper_X_X_chunk
(7 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM const_now WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(15 rows)
:PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
(5 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM const_now WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX WITH q1 AS (
SELECT * FROM const_now
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(5 rows)
-- JOIN
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Seq Scan on _hyper_X_X_chunk m1_2
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(6 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
(10 rows)
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(9 rows)
-- test UPDATE
:PREFIX UPDATE const_now SET value = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Update on const_now
Update on const_now
Update on _hyper_X_X_chunk const_now_1
-> Seq Scan on const_now
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1
Index Cond: ("time" > now())
(7 rows)
-- test DELETE
:PREFIX DELETE FROM const_now WHERE time > now();
QUERY PLAN
Delete on const_now
Delete on const_now
Delete on _hyper_X_X_chunk const_now_1
-> Seq Scan on const_now
Filter: (("time" > 'Mon Jan 01 00:00:00 1990 PST'::timestamp with time zone) AND ("time" > now()))
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1
Index Cond: ("time" > now())
(7 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should have one time filter false
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- no constification because it's not partitioning column
:PREFIX SELECT FROM const_now WHERE time2 > now();
QUERY PLAN
Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(2 rows)
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(5 rows)
DROP TABLE const_now;
-- test prepared statements
@ -507,3 +368,48 @@ QUERY PLAN
-> Seq Scan on _hyper_X_X_chunk m3
(8 rows)
-- test dst interaction with day intervals
SET timezone TO 'Europe/Berlin';
CREATE TABLE const_now_dst(time timestamptz not null);
SELECT table_name FROM create_hypertable('const_now_dst','time',chunk_time_interval:='30minutes'::interval);
table_name
const_now_dst
(1 row)
-- create 2 chunks
INSERT INTO const_now_dst SELECT '2022-03-27 03:15:00+02';
INSERT INTO const_now_dst SELECT '2022-03-27 03:45:00+02';
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 0:45+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:45:00 2022 CEST
(1 row)
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 1:15+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:15:00 2022 CEST
Sun Mar 27 03:45:00 2022 CEST
(2 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
DROP TABLE const_now_dst;

View File

@ -5,447 +5,306 @@ SET timescaledb.enable_chunk_append TO false;
SET timescaledb.enable_constraint_aware_append TO false;
SET timescaledb.current_timestamp_mock TO '1990-01-01';
\set PREFIX 'EXPLAIN (COSTS OFF, SUMMARY OFF, TIMING OFF)'
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '24h'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(7 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > now())
(13 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk
Index Cond: ((device_id = 2) AND ("time" >= (now() + '@ 10 mins'::interval)))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Append
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(10 rows)
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(7 rows)
-- variants we don't optimize
-- we do not allow interval with day or month components
:PREFIX SELECT FROM metrics WHERE time > now() - '1d'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1week'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(7 rows)
:PREFIX SELECT FROM metrics WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(7 rows)
:PREFIX SELECT FROM metrics WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(EXTRACT(epoch FROM now()), 0) > 0.5)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(EXTRACT(epoch FROM now()), 0) > 0.5)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(EXTRACT(epoch FROM now()), 0) > 0.5)
-> Seq Scan on _hyper_X_X_chunk
(10 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM metrics WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(22 rows)
:PREFIX SELECT FROM metrics WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_device_id_time_idx
Index Cond: (device_id = 2)
-> Bitmap Index Scan on _hyper_X_X_chunk_metrics_time_idx
Index Cond: (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))
(22 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM metrics WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
:PREFIX WITH q1 AS (
SELECT * FROM metrics
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(7 rows)
-- JOIN
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Seq Scan on _hyper_X_X_chunk m2_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Seq Scan on _hyper_X_X_chunk m1_2
-> Seq Scan on _hyper_X_X_chunk m1_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(16 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Seq Scan on _hyper_X_X_chunk m2_3
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
(13 rows)
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m1_3
Index Cond: ("time" > now())
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_2
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk m2_3
Index Cond: ("time" > now())
(16 rows)
-- test UPDATE
:PREFIX UPDATE metrics SET v0 = 0.1, v1 = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Custom Scan (HypertableModify)
-> Update on metrics
Update on _hyper_X_X_chunk metrics_1
Update on _hyper_X_X_chunk metrics_2
Update on _hyper_X_X_chunk metrics_3
-> Result
-> Append
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_1
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_2
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_3
Index Cond: ("time" > now())
(13 rows)
-- test DELETE
:PREFIX DELETE FROM metrics WHERE time > now();
QUERY PLAN
Custom Scan (HypertableModify)
-> Delete on metrics
Delete on _hyper_X_X_chunk metrics_1
Delete on _hyper_X_X_chunk metrics_2
Delete on _hyper_X_X_chunk metrics_3
-> Append
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_1
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_2
Index Cond: ("time" > now())
-> Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk metrics_3
Index Cond: ("time" > now())
(12 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM metrics WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
CREATE TABLE const_now(time timestamptz, time2 timestamptz, value float);
-- does not apply to non-hypertables
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Seq Scan on const_now
Filter: ("time" > now())
(2 rows)
-- create a test table
-- any query with successful now_constify will have 1 chunk while
-- others will have 2 chunks in plan
CREATE TABLE const_now(time timestamptz, time2 timestamptz, device_id int, value float);
SELECT table_name FROM create_hypertable('const_now','time');
NOTICE: adding not-null constraint to column "time"
table_name
const_now
(1 row)
INSERT INTO const_now SELECT '2000-01-01','2000-01-01',0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',1,0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',2,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',1,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5;
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= now())
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 24 hours'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() - '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 2 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() + '@ 3 days'::interval))
(2 rows)
:PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 7 days'::interval))
(2 rows)
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: ("time" > now())
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > now())
(4 rows)
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2;
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: (device_id = 2)
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
QUERY PLAN
Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" >= (now() + '@ 10 mins'::interval))
Filter: ((device_id = 2) OR (device_id = 3))
(3 rows)
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval)))
(2 rows)
-- variants we don't optimize
-- we do not allow interval with month components
:PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 mon'::interval))
(5 rows)
:PREFIX SELECT FROM const_now WHERE time > now()::date;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now())::date)
(5 rows)
:PREFIX SELECT FROM const_now WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
QUERY PLAN
Append
-> Result
One-Time Filter: (round(EXTRACT(epoch FROM now()), 0) > 0.5)
-> Seq Scan on _hyper_X_X_chunk
-> Result
One-Time Filter: (round(EXTRACT(epoch FROM now()), 0) > 0.5)
-> Seq Scan on _hyper_X_X_chunk
(7 rows)
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM const_now WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
QUERY PLAN
Append
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
-> Bitmap Heap Scan on _hyper_X_X_chunk
Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval)))
-> BitmapOr
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() - '@ 1 min'::interval))
-> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx
Index Cond: ("time" > (now() + '@ 1 min'::interval))
(15 rows)
:PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
QUERY PLAN
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
-> Seq Scan on _hyper_X_X_chunk
Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval))))
(5 rows)
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM const_now WHERE time > now()
) SELECT FROM q1;
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
:PREFIX WITH q1 AS (
SELECT * FROM const_now
) SELECT FROM q1 WHERE time > now();
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(5 rows)
-- JOIN
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m1_1
-> Seq Scan on _hyper_X_X_chunk m1_2
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(7 rows)
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now();
QUERY PLAN
Nested Loop
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(6 rows)
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now());
QUERY PLAN
Nested Loop
-> Append
-> Seq Scan on _hyper_X_X_chunk m2_1
-> Seq Scan on _hyper_X_X_chunk m2_2
-> Materialize
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
(10 rows)
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now()) WHERE m2.time > now();
QUERY PLAN
Nested Loop
-> Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_1
Index Cond: ("time" > now())
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1_2
Index Cond: ("time" > now())
-> Materialize
-> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2
Index Cond: ("time" > now())
(9 rows)
-- test UPDATE
:PREFIX UPDATE const_now SET value = EXTRACT(EPOCH FROM now()) WHERE time > now();
QUERY PLAN
Custom Scan (HypertableModify)
-> Update on const_now
Update on _hyper_X_X_chunk const_now_1
-> Result
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1
Index Cond: ("time" > now())
(6 rows)
-- test DELETE
:PREFIX DELETE FROM const_now WHERE time > now();
QUERY PLAN
Custom Scan (HypertableModify)
-> Delete on const_now
Delete on _hyper_X_X_chunk const_now_1
-> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1
Index Cond: ("time" > now())
(5 rows)
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- should have one time filter false
:PREFIX SELECT FROM const_now WHERE time > now();
QUERY PLAN
Result
One-Time Filter: false
Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > now())
(2 rows)
-- no constification because it's not partitioning column
:PREFIX SELECT FROM const_now WHERE time2 > now();
QUERY PLAN
Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(2 rows)
Append
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
-> Seq Scan on _hyper_X_X_chunk
Filter: (time2 > now())
(5 rows)
DROP TABLE const_now;
-- test prepared statements
@ -506,3 +365,48 @@ QUERY PLAN
-> Seq Scan on _hyper_X_X_chunk m3
(8 rows)
-- test dst interaction with day intervals
SET timezone TO 'Europe/Berlin';
CREATE TABLE const_now_dst(time timestamptz not null);
SELECT table_name FROM create_hypertable('const_now_dst','time',chunk_time_interval:='30minutes'::interval);
table_name
const_now_dst
(1 row)
-- create 2 chunks
INSERT INTO const_now_dst SELECT '2022-03-27 03:15:00+02';
INSERT INTO const_now_dst SELECT '2022-03-27 03:45:00+02';
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 0:45+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:45:00 2022 CEST
(1 row)
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 1:15+0'::timestamptz - '1d'::interval;
time
Sun Mar 27 03:15:00 2022 CEST
Sun Mar 27 03:45:00 2022 CEST
(2 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
QUERY PLAN
Append
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
-> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk
Index Cond: ("time" > (now() - '@ 1 day'::interval))
(5 rows)
DROP TABLE const_now_dst;

View File

@ -8,81 +8,84 @@ SET timescaledb.current_timestamp_mock TO '1990-01-01';
\set PREFIX 'EXPLAIN (COSTS OFF, SUMMARY OFF, TIMING OFF)'
-- create a test table
-- any query with successful now_constify will have 1 chunk while
-- others will have 2 chunks in plan
CREATE TABLE const_now(time timestamptz, time2 timestamptz, device_id int, value float);
SELECT table_name FROM create_hypertable('const_now','time');
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',1,0.5;
INSERT INTO const_now SELECT '1000-01-01','1000-01-01',2,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',1,0.5;
INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5;
-- test valid variants we are optimizing
-- all of these should have a constified value as filter
-- none of these initial tests will actually exclude chunks
-- because we want to see the constified now expression in
-- EXPLAIN output
:PREFIX SELECT FROM metrics WHERE time > now();
:PREFIX SELECT FROM metrics WHERE time >= now();
:PREFIX SELECT FROM metrics WHERE time > now() - '24h'::interval;
:PREFIX SELECT FROM metrics WHERE time > now() + '10m'::interval;
:PREFIX SELECT FROM metrics WHERE time >= now() - '10m'::interval;
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval;
:PREFIX SELECT FROM const_now WHERE time > now();
:PREFIX SELECT FROM const_now WHERE time >= now();
:PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval;
:PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval;
:PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval;
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval;
:PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval;
:PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval;
:PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval;
-- test bitmapheapscan
SET enable_indexscan TO false;
:PREFIX SELECT FROM metrics WHERE time > now();
:PREFIX SELECT FROM const_now WHERE time > now();
RESET enable_indexscan;
-- test multiple constraints
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND device_id = 2;
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
:PREFIX SELECT FROM metrics WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2;
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3);
:PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval;
-- variants we don't optimize
-- we do not allow interval with day or month components
:PREFIX SELECT FROM metrics WHERE time > now() - '1d'::interval;
:PREFIX SELECT FROM metrics WHERE time > now() - '1week'::interval;
:PREFIX SELECT FROM metrics WHERE time > now() - '1month'::interval;
:PREFIX SELECT FROM metrics WHERE time > now()::date;
:PREFIX SELECT FROM metrics WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
-- we do not allow interval with month components
:PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval;
:PREFIX SELECT FROM const_now WHERE time > now()::date;
:PREFIX SELECT FROM const_now WHERE round(EXTRACT(EPOCH FROM now())) > 0.5;
-- we only modify top-level ANDed now() expressions
:PREFIX SELECT FROM metrics WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
:PREFIX SELECT FROM metrics WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
:PREFIX SELECT FROM const_now WHERE time > now() - '1m'::interval OR time > now() + '1m'::interval;
:PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval);
-- CTE
:PREFIX WITH q1 AS (
SELECT * FROM metrics WHERE time > now()
SELECT * FROM const_now WHERE time > now()
) SELECT FROM q1;
:PREFIX WITH q1 AS (
SELECT * FROM metrics
SELECT * FROM const_now
) SELECT FROM q1 WHERE time > now();
-- JOIN
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now();
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m2.time > now();
:PREFIX SELECT FROM metrics m1, metrics m2 WHERE m1.time > now() AND m2.time > now();
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now();
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now();
:PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now();
-- only top-level constraints in WHERE clause are constified
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now());
:PREFIX SELECT FROM metrics m1 INNER JOIN metrics m2 ON (m1.time > now()) WHERE m2.time > now();
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now());
:PREFIX SELECT FROM const_now m1 INNER JOIN const_now m2 ON (m1.time > now()) WHERE m2.time > now();
-- test UPDATE
:PREFIX UPDATE metrics SET v0 = 0.1, v1 = EXTRACT(EPOCH FROM now()) WHERE time > now();
:PREFIX UPDATE const_now SET value = EXTRACT(EPOCH FROM now()) WHERE time > now();
-- test DELETE
:PREFIX DELETE FROM metrics WHERE time > now();
:PREFIX DELETE FROM const_now WHERE time > now();
-- test chunks actually get excluded
-- should exclude all
SET timescaledb.current_timestamp_mock TO '2010-01-01';
:PREFIX SELECT FROM metrics WHERE time > now();
:PREFIX SELECT FROM const_now WHERE time > now();
-- should exclude all but 1 chunk
SET timescaledb.current_timestamp_mock TO '2000-01-14';
:PREFIX SELECT FROM metrics WHERE time > now();
CREATE TABLE const_now(time timestamptz, time2 timestamptz, value float);
-- does not apply to non-hypertables
:PREFIX SELECT FROM const_now WHERE time > now();
SELECT table_name FROM create_hypertable('const_now','time');
INSERT INTO const_now SELECT '2000-01-01','2000-01-01',0.5;
-- should have one time filter false
:PREFIX SELECT FROM const_now WHERE time > now();
@ -118,3 +121,27 @@ DROP TABLE prep_const_now;
WHERE
EXISTS (SELECT * FROM metrics_tstz AS m3 WHERE m2.time > now());
-- test dst interaction with day intervals
SET timezone TO 'Europe/Berlin';
CREATE TABLE const_now_dst(time timestamptz not null);
SELECT table_name FROM create_hypertable('const_now_dst','time',chunk_time_interval:='30minutes'::interval);
-- create 2 chunks
INSERT INTO const_now_dst SELECT '2022-03-27 03:15:00+02';
INSERT INTO const_now_dst SELECT '2022-03-27 03:45:00+02';
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 0:45+0'::timestamptz - '1d'::interval;
SELECT * FROM const_now_dst WHERE time >= '2022-03-28 1:15+0'::timestamptz - '1d'::interval;
SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0';
-- must have 2 chunks in plan
:PREFIX SELECT FROM const_now_dst WHERE time > now() - '1day'::interval;
DROP TABLE const_now_dst;