mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 18:43:18 +08:00
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:
parent
a6b5f9002c
commit
12574dc8ec
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user