\o /dev/null \ir include/insert_two_partitions.sql \ir create_single_db.sql SET client_min_messages = WARNING; DROP DATABASE IF EXISTS single; SET client_min_messages = NOTICE; CREATE DATABASE single; \c single CREATE EXTENSION IF NOT EXISTS timescaledb; \c single CREATE TABLE PUBLIC."two_Partitions" ( "timeCustom" BIGINT NOT NULL, device_id TEXT NOT NULL, series_0 DOUBLE PRECISION NULL, series_1 DOUBLE PRECISION NULL, series_2 DOUBLE PRECISION NULL, series_bool BOOLEAN NULL ); CREATE INDEX ON PUBLIC."two_Partitions" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, device_id); SELECT * FROM create_hypertable('"public"."two_Partitions"'::regclass, 'timeCustom'::name, 'device_id'::name, associated_schema_name=>'_timescaledb_internal'::text, number_partitions => 2); \set QUIET off BEGIN; \COPY public."two_Partitions" FROM 'data/ds1_dev1_1.tsv' NULL AS ''; COMMIT; INSERT INTO public."two_Partitions"("timeCustom", device_id, series_0, series_1) VALUES (1257987600000000000, 'dev1', 1.5, 1), (1257987600000000000, 'dev1', 1.5, 2), (1257894000000000000, 'dev2', 1.5, 1), (1257894002000000000, 'dev1', 2.5, 3); INSERT INTO "two_Partitions"("timeCustom", device_id, series_0, series_1) VALUES (1257894000000000000, 'dev2', 1.5, 2); \set QUIET on \o SELECT * FROM PUBLIC."two_Partitions"; timeCustom | device_id | series_0 | series_1 | series_2 | series_bool ---------------------+-----------+----------+----------+----------+------------- 1257894000000000000 | dev1 | 1.5 | 1 | 2 | t 1257894000000000000 | dev1 | 1.5 | 2 | | 1257894000000001000 | dev1 | 2.5 | 3 | | 1257894001000000000 | dev1 | 3.5 | 4 | | 1257894002000000000 | dev1 | 5.5 | 6 | | t 1257894002000000000 | dev1 | 5.5 | 7 | | f 1257894002000000000 | dev1 | 2.5 | 3 | | 1257897600000000000 | dev1 | 4.5 | 5 | | f 1257987600000000000 | dev1 | 1.5 | 1 | | 1257987600000000000 | dev1 | 1.5 | 2 | | 1257894000000000000 | dev2 | 1.5 | 1 | | 1257894000000000000 | dev2 | 1.5 | 2 | | (12 rows) EXPLAIN (verbose ON, costs off) SELECT * FROM PUBLIC."two_Partitions"; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool -> Seq Scan on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.device_id, _hyper_1_1_chunk.series_0, _hyper_1_1_chunk.series_1, _hyper_1_1_chunk.series_2, _hyper_1_1_chunk.series_bool -> Seq Scan on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.device_id, _hyper_1_2_chunk.series_0, _hyper_1_2_chunk.series_1, _hyper_1_2_chunk.series_2, _hyper_1_2_chunk.series_bool -> Seq Scan on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.device_id, _hyper_1_3_chunk.series_0, _hyper_1_3_chunk.series_1, _hyper_1_3_chunk.series_2, _hyper_1_3_chunk.series_bool -> Seq Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool (11 rows) \echo "The following queries should NOT scan two_Partitions._hyper_1_1_0_partition" "The following queries should NOT scan two_Partitions._hyper_1_1_0_partition" EXPLAIN (verbose ON, costs off) SELECT * FROM PUBLIC."two_Partitions" WHERE device_id = 'dev2'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool Filter: (("two_Partitions".device_id = 'dev2'::text) AND (_timescaledb_internal.get_partition_for_key("two_Partitions".device_id, 32768) = '17190'::smallint)) -> Bitmap Heap Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool Recheck Cond: (_hyper_1_4_chunk.device_id = 'dev2'::text) Filter: (_timescaledb_internal.get_partition_for_key(_hyper_1_4_chunk.device_id, 32768) = '17190'::smallint) -> Bitmap Index Scan on "22-two_Partitions_device_id_timeCustom_idx" Index Cond: (_hyper_1_4_chunk.device_id = 'dev2'::text) (10 rows) EXPLAIN (verbose ON, costs off) SELECT * FROM PUBLIC."two_Partitions" WHERE device_id = 'dev'||'2'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool Filter: (("two_Partitions".device_id = 'dev2'::text) AND (_timescaledb_internal.get_partition_for_key("two_Partitions".device_id, 32768) = '17190'::smallint)) -> Bitmap Heap Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool Recheck Cond: (_hyper_1_4_chunk.device_id = 'dev2'::text) Filter: (_timescaledb_internal.get_partition_for_key(_hyper_1_4_chunk.device_id, 32768) = '17190'::smallint) -> Bitmap Index Scan on "22-two_Partitions_device_id_timeCustom_idx" Index Cond: (_hyper_1_4_chunk.device_id = 'dev2'::text) (10 rows) EXPLAIN (verbose ON, costs off) SELECT * FROM PUBLIC."two_Partitions" WHERE 'dev'||'2' = device_id; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool Filter: (('dev2'::text = "two_Partitions".device_id) AND (_timescaledb_internal.get_partition_for_key("two_Partitions".device_id, 32768) = '17190'::smallint)) -> Bitmap Heap Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool Recheck Cond: ('dev2'::text = _hyper_1_4_chunk.device_id) Filter: (_timescaledb_internal.get_partition_for_key(_hyper_1_4_chunk.device_id, 32768) = '17190'::smallint) -> Bitmap Index Scan on "22-two_Partitions_device_id_timeCustom_idx" Index Cond: ('dev2'::text = _hyper_1_4_chunk.device_id) (10 rows) --test integer partition key CREATE TABLE "int_part"(time timestamp, object_id int, temp float); SELECT create_hypertable('"int_part"', 'time', 'object_id', 2); create_hypertable ------------------- (1 row) INSERT INTO "int_part" VALUES('2017-01-20T09:00:01', 1, 22.5); SELECT * FROM "int_part" WHERE object_id = 1; time | object_id | temp --------------------------+-----------+------ Fri Jan 20 09:00:01 2017 | 1 | 22.5 (1 row) --make sure this touches only one partititon EXPLAIN (verbose ON, costs off) SELECT * FROM "int_part" WHERE object_id = 1; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------- Append -> Seq Scan on public.int_part Output: int_part."time", int_part.object_id, int_part.temp Filter: ((int_part.object_id = 1) AND (_timescaledb_internal.get_partition_for_key((int_part.object_id)::text, 32768) = '11001'::smallint)) -> Bitmap Heap Scan on _timescaledb_internal._hyper_2_5_chunk Output: _hyper_2_5_chunk."time", _hyper_2_5_chunk.object_id, _hyper_2_5_chunk.temp Recheck Cond: (_hyper_2_5_chunk.object_id = 1) Filter: (_timescaledb_internal.get_partition_for_key((_hyper_2_5_chunk.object_id)::text, 32768) = '11001'::smallint) -> Bitmap Index Scan on "29-int_part_object_id_time_idx" Index Cond: (_hyper_2_5_chunk.object_id = 1) (10 rows) --TODO: handle this later? --EXPLAIN (verbose ON, costs off) SELECT * FROM "two_Partitions" WHERE device_id IN ('dev2', 'dev21'); \echo "The following shows non-aggregated queries with time desc using merge append" "The following shows non-aggregated queries with time desc using merge append" EXPLAIN (verbose ON, costs off)SELECT * FROM PUBLIC."two_Partitions" ORDER BY "timeCustom" DESC NULLS LAST limit 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Limit Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool -> Merge Append Sort Key: "two_Partitions"."timeCustom" DESC NULLS LAST -> Index Scan using "two_Partitions_timeCustom_device_id_idx" on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool -> Index Scan using "2-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.device_id, _hyper_1_1_chunk.series_0, _hyper_1_1_chunk.series_1, _hyper_1_1_chunk.series_2, _hyper_1_1_chunk.series_bool -> Index Scan using "9-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.device_id, _hyper_1_2_chunk.series_0, _hyper_1_2_chunk.series_1, _hyper_1_2_chunk.series_2, _hyper_1_2_chunk.series_bool -> Index Scan using "16-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.device_id, _hyper_1_3_chunk.series_0, _hyper_1_3_chunk.series_1, _hyper_1_3_chunk.series_2, _hyper_1_3_chunk.series_bool -> Index Scan using "23-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool (14 rows) --shows that more specific indexes are used if the WHERE clauses "match", uses the series_1 index here. EXPLAIN (verbose ON, costs off)SELECT * FROM PUBLIC."two_Partitions" WHERE series_1 IS NOT NULL ORDER BY "timeCustom" DESC NULLS LAST limit 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Limit Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool -> Merge Append Sort Key: "two_Partitions"."timeCustom" DESC NULLS LAST -> Index Scan using "two_Partitions_timeCustom_device_id_idx" on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool Filter: ("two_Partitions".series_1 IS NOT NULL) -> Index Scan using "5-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.device_id, _hyper_1_1_chunk.series_0, _hyper_1_1_chunk.series_1, _hyper_1_1_chunk.series_2, _hyper_1_1_chunk.series_bool -> Index Scan using "12-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.device_id, _hyper_1_2_chunk.series_0, _hyper_1_2_chunk.series_1, _hyper_1_2_chunk.series_2, _hyper_1_2_chunk.series_bool -> Index Scan using "19-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.device_id, _hyper_1_3_chunk.series_0, _hyper_1_3_chunk.series_1, _hyper_1_3_chunk.series_2, _hyper_1_3_chunk.series_bool -> Index Scan using "26-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool (15 rows) --here the "match" is implication series_1 > 1 => series_1 IS NOT NULL EXPLAIN (verbose ON, costs off)SELECT * FROM PUBLIC."two_Partitions" WHERE series_1 > 1 ORDER BY "timeCustom" DESC NULLS LAST limit 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Limit Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool -> Merge Append Sort Key: "two_Partitions"."timeCustom" DESC NULLS LAST -> Index Scan using "two_Partitions_timeCustom_device_id_idx" on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".device_id, "two_Partitions".series_0, "two_Partitions".series_1, "two_Partitions".series_2, "two_Partitions".series_bool Filter: ("two_Partitions".series_1 > '1'::double precision) -> Index Scan using "5-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.device_id, _hyper_1_1_chunk.series_0, _hyper_1_1_chunk.series_1, _hyper_1_1_chunk.series_2, _hyper_1_1_chunk.series_bool Index Cond: (_hyper_1_1_chunk.series_1 > '1'::double precision) -> Index Scan using "12-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.device_id, _hyper_1_2_chunk.series_0, _hyper_1_2_chunk.series_1, _hyper_1_2_chunk.series_2, _hyper_1_2_chunk.series_bool Index Cond: (_hyper_1_2_chunk.series_1 > '1'::double precision) -> Index Scan using "19-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.device_id, _hyper_1_3_chunk.series_0, _hyper_1_3_chunk.series_1, _hyper_1_3_chunk.series_2, _hyper_1_3_chunk.series_bool Index Cond: (_hyper_1_3_chunk.series_1 > '1'::double precision) -> Index Scan using "26-two_Partitions_timeCustom_series_1_idx" on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.device_id, _hyper_1_4_chunk.series_0, _hyper_1_4_chunk.series_1, _hyper_1_4_chunk.series_2, _hyper_1_4_chunk.series_bool Index Cond: (_hyper_1_4_chunk.series_1 > '1'::double precision) (19 rows) --note that without time transform things work too EXPLAIN (verbose ON, costs off)SELECT "timeCustom" t, min(series_0) FROM PUBLIC."two_Partitions" GROUP BY t ORDER BY t DESC NULLS LAST limit 2; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Limit Output: "two_Partitions"."timeCustom", (min("two_Partitions".series_0)) -> GroupAggregate Output: "two_Partitions"."timeCustom", min("two_Partitions".series_0) Group Key: "two_Partitions"."timeCustom" -> Merge Append Sort Key: "two_Partitions"."timeCustom" DESC NULLS LAST -> Index Scan using "two_Partitions_timeCustom_device_id_idx" on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".series_0 -> Index Scan using "2-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.series_0 -> Index Scan using "9-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.series_0 -> Index Scan using "16-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.series_0 -> Index Scan using "23-two_Partitions_timeCustom_device_id_idx" on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.series_0 (17 rows) --TODO: time transform doesn't work EXPLAIN (verbose ON, costs off)SELECT "timeCustom"/10 t, min(series_0) FROM PUBLIC."two_Partitions" GROUP BY t ORDER BY t DESC NULLS LAST limit 2; QUERY PLAN -------------------------------------------------------------------------------------------------- Limit Output: (("two_Partitions"."timeCustom" / 10)), (min("two_Partitions".series_0)) -> Sort Output: (("two_Partitions"."timeCustom" / 10)), (min("two_Partitions".series_0)) Sort Key: (("two_Partitions"."timeCustom" / 10)) DESC NULLS LAST -> HashAggregate Output: (("two_Partitions"."timeCustom" / 10)), min("two_Partitions".series_0) Group Key: ("two_Partitions"."timeCustom" / 10) -> Result Output: ("two_Partitions"."timeCustom" / 10), "two_Partitions".series_0 -> Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".series_0 -> Seq Scan on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.series_0 (21 rows) EXPLAIN (verbose ON, costs off)SELECT "timeCustom"%10 t, min(series_0) FROM PUBLIC."two_Partitions" GROUP BY t ORDER BY t DESC NULLS LAST limit 2; QUERY PLAN -------------------------------------------------------------------------------------------------------- Limit Output: (("two_Partitions"."timeCustom" % '10'::bigint)), (min("two_Partitions".series_0)) -> Sort Output: (("two_Partitions"."timeCustom" % '10'::bigint)), (min("two_Partitions".series_0)) Sort Key: (("two_Partitions"."timeCustom" % '10'::bigint)) DESC NULLS LAST -> HashAggregate Output: (("two_Partitions"."timeCustom" % '10'::bigint)), min("two_Partitions".series_0) Group Key: ("two_Partitions"."timeCustom" % '10'::bigint) -> Result Output: ("two_Partitions"."timeCustom" % '10'::bigint), "two_Partitions".series_0 -> Append -> Seq Scan on public."two_Partitions" Output: "two_Partitions"."timeCustom", "two_Partitions".series_0 -> Seq Scan on _timescaledb_internal._hyper_1_1_chunk Output: _hyper_1_1_chunk."timeCustom", _hyper_1_1_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_2_chunk Output: _hyper_1_2_chunk."timeCustom", _hyper_1_2_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_3_chunk Output: _hyper_1_3_chunk."timeCustom", _hyper_1_3_chunk.series_0 -> Seq Scan on _timescaledb_internal._hyper_1_4_chunk Output: _hyper_1_4_chunk."timeCustom", _hyper_1_4_chunk.series_0 (21 rows)