diff --git a/.unreleased/pr_7318 b/.unreleased/pr_7318 new file mode 100644 index 00000000000..bf74089f938 --- /dev/null +++ b/.unreleased/pr_7318 @@ -0,0 +1 @@ +Fixes: #7318: Fix chunk skipping range filtering diff --git a/src/hypertable_restrict_info.c b/src/hypertable_restrict_info.c index 1f9f617910f..691a3468a61 100644 --- a/src/hypertable_restrict_info.c +++ b/src/hypertable_restrict_info.c @@ -175,81 +175,6 @@ dimension_restrict_info_open_add(DimensionRestrictInfoOpen *dri, StrategyNumber return restriction_added; } -/* - * for DIMENSION_TYPE_STATS entries, we need to use regular bounded strategies. - * We can have multiple entries satisfying the inputs. It basically becomes a - * problem of: - * - * "given an input value, find all ranges which encompass that value" - * - * For "column >= constant" (e.g id >= 9), the check has to be: - * - * start_range >= 9 OR end_range >= 9 (second check covers +INF) - * - * For "column <= constant" (e.g id <= 90), the check has to be: - * - * start_range <= 90 OR end_range <= 90 (first check covers -INF) - * - * For "column == constant" (e.g id = 9) - * - * start_range <= 9 OR end_range >= 9 (covers +INF to -INF) - */ -static bool -dimension_restrict_info_range_add(DimensionRestrictInfoOpen *dri, StrategyNumber strategy, - Oid collation, DimensionValues *dimvalues) -{ - ListCell *item; - bool restriction_added = false; - - /* can't handle IN/ANY with multiple values */ - if (dimvalues->use_or && list_length(dimvalues->values) > 1) - return false; - - foreach (item, dimvalues->values) - { - Oid restype; - Datum datum = ts_dimension_transform_value(dri->base.dimension, - collation, - PointerGetDatum(lfirst(item)), - dimvalues->type, - &restype); - int64 value = ts_time_value_to_internal_or_infinite(datum, restype); - - switch (strategy) - { - case BTLessEqualStrategyNumber: - case BTLessStrategyNumber: /* e.g: id <= 90 */ - if (dri->upper_strategy == InvalidStrategy || value < dri->upper_bound) - { - dri->upper_strategy = strategy; - dri->upper_bound = value; - restriction_added = true; - } - break; - case BTGreaterEqualStrategyNumber: - case BTGreaterStrategyNumber: /* e.g: id >= 9 */ - if (dri->lower_strategy == InvalidStrategy || value > dri->lower_bound) - { - dri->lower_strategy = strategy; - dri->lower_bound = value; - restriction_added = true; - } - break; - case BTEqualStrategyNumber: /* e.g: id = 9 */ - dri->lower_bound = value; - dri->upper_bound = value; - dri->lower_strategy = BTEqualStrategyNumber; - dri->upper_strategy = BTEqualStrategyNumber; - restriction_added = true; - break; - default: - /* unsupported strategy */ - break; - } - } - return restriction_added; -} - static List * dimension_restrict_info_get_partitions(DimensionRestrictInfoClosed *dri, Oid collation, List *values) @@ -330,10 +255,10 @@ dimension_restrict_info_add(DimensionRestrictInfo *dri, int strategy, Oid collat values); case DIMENSION_TYPE_STATS: /* we reuse the DimensionRestrictInfoOpen structure for these */ - return dimension_restrict_info_range_add((DimensionRestrictInfoOpen *) dri, - strategy, - collation, - values); + return dimension_restrict_info_open_add((DimensionRestrictInfoOpen *) dri, + strategy, + collation, + values); case DIMENSION_TYPE_CLOSED: return dimension_restrict_info_closed_add((DimensionRestrictInfoClosed *) dri, strategy, diff --git a/src/ts_catalog/chunk_column_stats.c b/src/ts_catalog/chunk_column_stats.c index d1872f27063..0b64d8ffd2c 100644 --- a/src/ts_catalog/chunk_column_stats.c +++ b/src/ts_catalog/chunk_column_stats.c @@ -1071,7 +1071,6 @@ ts_chunk_column_stats_get_chunk_ids_by_scan(DimensionRestrictInfo *dri) ScanIterator it; List *chunkids = NIL; DimensionRestrictInfoOpen *open; - bool check_both = false; Assert(dri && dri->dimension->type == DIMENSION_TYPE_STATS); @@ -1082,25 +1081,6 @@ ts_chunk_column_stats_get_chunk_ids_by_scan(DimensionRestrictInfo *dri) open = (DimensionRestrictInfoOpen *) dri; - /* - * Since we need to find chunks with overlapping ranges. We use checks on both the - * lower_bound and the upper_bound. - */ - if (open->upper_strategy != InvalidStrategy && open->lower_strategy != InvalidStrategy) - check_both = true; - - if (open->upper_strategy == InvalidStrategy) - { - open->upper_strategy = open->lower_strategy; - open->upper_bound = open->lower_bound; - } - - if (open->lower_strategy == InvalidStrategy) - { - open->lower_strategy = open->upper_strategy; - open->lower_bound = open->upper_bound; - } - /* * We need to get all chunks matching the hypertable ID and the column name. */ @@ -1143,18 +1123,6 @@ ts_chunk_column_stats_get_chunk_ids_by_scan(DimensionRestrictInfo *dri) goto done; } - /* - * If both upper and lower bounds have been specified then we need to check - * if that range overlaps (subset, superset, intersect) with the current fd entry - * values - */ - if (check_both) - { - /* range is before or after our fd range_start/range_end values */ - if (open->upper_bound < fd->range_start || open->lower_bound > fd->range_end) - goto done; - } - /* * All data is in int8 format so we do regular comparisons. Also, it's an OR * check so prepare to short circuit if one evaluates to true. @@ -1166,78 +1134,37 @@ ts_chunk_column_stats_get_chunk_ids_by_scan(DimensionRestrictInfo *dri) { case BTLessEqualStrategyNumber: /* e.g: id <= 90 */ { - /* range_end is exclusive, so check accordingly */ - if ((fd->range_end - 1) <= open->upper_bound) - matched = check_both ? false : true; + matched = fd->range_start <= open->upper_bound; } break; case BTLessStrategyNumber: /* e.g: id < 90 */ { - /* range_end is exclusive, so check accordingly */ - if ((fd->range_end - 1) < open->upper_bound) - matched = check_both ? false : true; - } - break; - case BTGreaterEqualStrategyNumber: /* e.g: id >= 90 */ - { - /* range_end is exclusive, so check accordingly */ - if ((fd->range_end - 1) >= open->upper_bound) - matched = check_both ? false : true; - } - break; - case BTGreaterStrategyNumber: /* e.g: id > 9 */ - { - /* range_end is exclusive, so check accordingly */ - if ((fd->range_end - 1) > open->upper_bound) - matched = check_both ? false : true; - } - break; - case BTEqualStrategyNumber: /* e.g: id == 9 */ - { - /* need to check for both range_start and range_end */ - if (fd->range_start <= open->lower_bound && - (fd->range_end - 1) >= open->upper_bound) - matched = true; + matched = fd->range_start < open->upper_bound; } break; default: - /* unsupported strategy */ + open->upper_strategy = InvalidStrategy; break; } - if (matched) + if (open->upper_strategy != InvalidStrategy && !matched) goto done; /* range_end checks didn't match, check for range_start now */ switch (open->lower_strategy) { - case BTLessEqualStrategyNumber: - { - if (fd->range_start <= open->lower_bound) - matched = true; - } - break; - case BTLessStrategyNumber: - { - if (fd->range_start < open->lower_bound) - matched = true; - } - break; case BTGreaterEqualStrategyNumber: { - if (fd->range_start >= open->lower_bound) - matched = true; + /* range_end is exclusive */ + matched = (fd->range_end - 1) >= open->lower_bound; } break; case BTGreaterStrategyNumber: { - /* range_start is inclusive */ - if (fd->range_start >= open->lower_bound) - matched = true; + /* range_end is exclusive */ + matched = (fd->range_end - 1) > open->lower_bound; } break; - case BTEqualStrategyNumber: - /* already handled above with upper_strategy */ default: /* unsupported strategy */ break; diff --git a/tsl/test/expected/chunk_column_stats-14.out b/tsl/test/expected/chunk_column_stats-14.out index a7679f6a19d..d66f7163bab 100644 --- a/tsl/test/expected/chunk_column_stats-14.out +++ b/tsl/test/expected/chunk_column_stats-14.out @@ -205,11 +205,35 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I -- A query using a WHERE clause on "sensor_id" column will scan the proper chunk -- due to chunk exclusion using min/max ranges calculated above -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9; +-- First chunk has [start,end) values of [1,9), here we confirm that its being +-- filtered out when we are not hitting that range. +-- Query ranges outside of chunk stats, should not include first chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 1) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 0; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 0) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 8; QUERY PLAN ------------------------------ Seq Scan on _hyper_1_2_chunk - Filter: (sensor_id > 9) + Filter: (sensor_id > 8) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 9; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 9) (2 rows) :PREFIX SELECT * FROM sample_table WHERE sensor_id = 10; @@ -219,6 +243,118 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id = 10) (2 rows) +-- Query intersecting ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id = 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id = 7) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id = 7) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id < 2) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 2) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 3; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > 3) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > 3) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id <= 1) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 1) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id >= 8) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 8) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8 AND sensor_id <= 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 8) AND (sensor_id <= 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 8) AND (sensor_id <= 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 4 AND sensor_id > -5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 6 AND sensor_id < 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 6) AND (sensor_id < 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 6) AND (sensor_id < 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 5 AND sensor_id > -1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) +(6 rows) + +-- Query chunk superset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > -2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > '-2'::integer) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > '-2'::integer) +(6 rows) + :PREFIX SELECT * FROM sample_table WHERE sensor_id < 11; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -230,22 +366,86 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id < 11) (6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9 and sensor_id < 20; - QUERY PLAN --------------------------------------------------- - Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 9) AND (sensor_id < 20)) -(2 rows) +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 1 AND sensor_id <= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 1) AND (sensor_id <= 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 1) AND (sensor_id <= 8)) +(6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 1 and sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 0 AND sensor_id < 9; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Append -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk - Index Cond: ((sensor_id > 1) AND (sensor_id < 7)) + Index Cond: ((sensor_id > 0) AND (sensor_id < 9)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 0) AND (sensor_id < 9)) +(6 rows) + +-- Query chunk subset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 2 AND sensor_id < 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 2) AND (sensor_id < 7)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 2) AND (sensor_id < 7)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 3 AND sensor_id <= 6; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 3) AND (sensor_id <= 6)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 3) AND (sensor_id <= 6)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 4 AND sensor_id <= 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 4) AND (sensor_id <= 5)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 4) AND (sensor_id <= 5)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 6 AND sensor_id < 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 6) AND (sensor_id < 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 6) AND (sensor_id < 8)) +(6 rows) + +-- Query ranges with OR clause will not work properly due to the way +-- hypertable expansion works as of now. Once we fix that, it should +-- fix the issue here too. +-- Should not include but it does. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1 OR sensor_id > 8; + QUERY PLAN +------------------------------------------------------------ + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Seq Scan on compress_hyper_2_3_chunk + Filter: ((sensor_id < 1) OR (sensor_id > 8)) -> Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 1) AND (sensor_id < 7)) + Filter: ((sensor_id < 1) OR (sensor_id > 8)) (6 rows) -- Executor startup time exclusion will also use these ranges appropriately diff --git a/tsl/test/expected/chunk_column_stats-15.out b/tsl/test/expected/chunk_column_stats-15.out index 050efb7041a..ff6eac98555 100644 --- a/tsl/test/expected/chunk_column_stats-15.out +++ b/tsl/test/expected/chunk_column_stats-15.out @@ -205,11 +205,35 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I -- A query using a WHERE clause on "sensor_id" column will scan the proper chunk -- due to chunk exclusion using min/max ranges calculated above -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9; +-- First chunk has [start,end) values of [1,9), here we confirm that its being +-- filtered out when we are not hitting that range. +-- Query ranges outside of chunk stats, should not include first chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 1) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 0; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 0) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 8; QUERY PLAN ------------------------------ Seq Scan on _hyper_1_2_chunk - Filter: (sensor_id > 9) + Filter: (sensor_id > 8) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 9; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 9) (2 rows) :PREFIX SELECT * FROM sample_table WHERE sensor_id = 10; @@ -219,6 +243,118 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id = 10) (2 rows) +-- Query intersecting ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id = 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id = 7) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id = 7) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id < 2) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 2) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 3; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > 3) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > 3) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id <= 1) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 1) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id >= 8) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 8) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8 AND sensor_id <= 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 8) AND (sensor_id <= 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 8) AND (sensor_id <= 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 4 AND sensor_id > -5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 6 AND sensor_id < 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 6) AND (sensor_id < 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 6) AND (sensor_id < 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 5 AND sensor_id > -1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) +(6 rows) + +-- Query chunk superset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > -2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > '-2'::integer) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > '-2'::integer) +(6 rows) + :PREFIX SELECT * FROM sample_table WHERE sensor_id < 11; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -230,22 +366,86 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id < 11) (6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9 and sensor_id < 20; - QUERY PLAN --------------------------------------------------- - Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 9) AND (sensor_id < 20)) -(2 rows) +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 1 AND sensor_id <= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 1) AND (sensor_id <= 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 1) AND (sensor_id <= 8)) +(6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 1 and sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 0 AND sensor_id < 9; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Append -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk - Index Cond: ((sensor_id > 1) AND (sensor_id < 7)) + Index Cond: ((sensor_id > 0) AND (sensor_id < 9)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 0) AND (sensor_id < 9)) +(6 rows) + +-- Query chunk subset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 2 AND sensor_id < 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 2) AND (sensor_id < 7)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 2) AND (sensor_id < 7)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 3 AND sensor_id <= 6; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 3) AND (sensor_id <= 6)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 3) AND (sensor_id <= 6)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 4 AND sensor_id <= 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 4) AND (sensor_id <= 5)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 4) AND (sensor_id <= 5)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 6 AND sensor_id < 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 6) AND (sensor_id < 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 6) AND (sensor_id < 8)) +(6 rows) + +-- Query ranges with OR clause will not work properly due to the way +-- hypertable expansion works as of now. Once we fix that, it should +-- fix the issue here too. +-- Should not include but it does. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1 OR sensor_id > 8; + QUERY PLAN +------------------------------------------------------------ + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Seq Scan on compress_hyper_2_3_chunk + Filter: ((sensor_id < 1) OR (sensor_id > 8)) -> Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 1) AND (sensor_id < 7)) + Filter: ((sensor_id < 1) OR (sensor_id > 8)) (6 rows) -- Executor startup time exclusion will also use these ranges appropriately diff --git a/tsl/test/expected/chunk_column_stats-16.out b/tsl/test/expected/chunk_column_stats-16.out index 050efb7041a..ff6eac98555 100644 --- a/tsl/test/expected/chunk_column_stats-16.out +++ b/tsl/test/expected/chunk_column_stats-16.out @@ -205,11 +205,35 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I -- A query using a WHERE clause on "sensor_id" column will scan the proper chunk -- due to chunk exclusion using min/max ranges calculated above -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9; +-- First chunk has [start,end) values of [1,9), here we confirm that its being +-- filtered out when we are not hitting that range. +-- Query ranges outside of chunk stats, should not include first chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 1) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 0; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 0) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 8; QUERY PLAN ------------------------------ Seq Scan on _hyper_1_2_chunk - Filter: (sensor_id > 9) + Filter: (sensor_id > 8) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 9; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 9) (2 rows) :PREFIX SELECT * FROM sample_table WHERE sensor_id = 10; @@ -219,6 +243,118 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id = 10) (2 rows) +-- Query intersecting ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id = 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id = 7) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id = 7) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id < 2) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 2) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 3; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > 3) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > 3) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id <= 1) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 1) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id >= 8) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 8) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8 AND sensor_id <= 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 8) AND (sensor_id <= 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 8) AND (sensor_id <= 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 4 AND sensor_id > -5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 6 AND sensor_id < 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 6) AND (sensor_id < 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 6) AND (sensor_id < 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 5 AND sensor_id > -1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) +(6 rows) + +-- Query chunk superset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > -2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > '-2'::integer) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > '-2'::integer) +(6 rows) + :PREFIX SELECT * FROM sample_table WHERE sensor_id < 11; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -230,22 +366,86 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id < 11) (6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9 and sensor_id < 20; - QUERY PLAN --------------------------------------------------- - Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 9) AND (sensor_id < 20)) -(2 rows) +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 1 AND sensor_id <= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 1) AND (sensor_id <= 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 1) AND (sensor_id <= 8)) +(6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 1 and sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 0 AND sensor_id < 9; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Append -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk - Index Cond: ((sensor_id > 1) AND (sensor_id < 7)) + Index Cond: ((sensor_id > 0) AND (sensor_id < 9)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 0) AND (sensor_id < 9)) +(6 rows) + +-- Query chunk subset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 2 AND sensor_id < 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 2) AND (sensor_id < 7)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 2) AND (sensor_id < 7)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 3 AND sensor_id <= 6; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 3) AND (sensor_id <= 6)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 3) AND (sensor_id <= 6)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 4 AND sensor_id <= 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 4) AND (sensor_id <= 5)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 4) AND (sensor_id <= 5)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 6 AND sensor_id < 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 6) AND (sensor_id < 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 6) AND (sensor_id < 8)) +(6 rows) + +-- Query ranges with OR clause will not work properly due to the way +-- hypertable expansion works as of now. Once we fix that, it should +-- fix the issue here too. +-- Should not include but it does. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1 OR sensor_id > 8; + QUERY PLAN +------------------------------------------------------------ + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Seq Scan on compress_hyper_2_3_chunk + Filter: ((sensor_id < 1) OR (sensor_id > 8)) -> Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 1) AND (sensor_id < 7)) + Filter: ((sensor_id < 1) OR (sensor_id > 8)) (6 rows) -- Executor startup time exclusion will also use these ranges appropriately diff --git a/tsl/test/expected/chunk_column_stats-17.out b/tsl/test/expected/chunk_column_stats-17.out index 050efb7041a..ff6eac98555 100644 --- a/tsl/test/expected/chunk_column_stats-17.out +++ b/tsl/test/expected/chunk_column_stats-17.out @@ -205,11 +205,35 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I -- A query using a WHERE clause on "sensor_id" column will scan the proper chunk -- due to chunk exclusion using min/max ranges calculated above -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9; +-- First chunk has [start,end) values of [1,9), here we confirm that its being +-- filtered out when we are not hitting that range. +-- Query ranges outside of chunk stats, should not include first chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 1) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 0; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 0) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 8; QUERY PLAN ------------------------------ Seq Scan on _hyper_1_2_chunk - Filter: (sensor_id > 9) + Filter: (sensor_id > 8) +(2 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 9; + QUERY PLAN +------------------------------ + Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 9) (2 rows) :PREFIX SELECT * FROM sample_table WHERE sensor_id = 10; @@ -219,6 +243,118 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id = 10) (2 rows) +-- Query intersecting ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id = 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id = 7) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id = 7) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id < 2) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id < 2) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 3; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > 3) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > 3) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id <= 1) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id <= 1) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id >= 8) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id >= 8) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8 AND sensor_id <= 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 8) AND (sensor_id <= 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 8) AND (sensor_id <= 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 4 AND sensor_id > -5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 4) AND (sensor_id > '-5'::integer)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 6 AND sensor_id < 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 6) AND (sensor_id < 10)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 6) AND (sensor_id < 10)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 5 AND sensor_id > -1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id <= 5) AND (sensor_id > '-1'::integer)) +(6 rows) + +-- Query chunk superset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > -2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: (sensor_id > '-2'::integer) + -> Seq Scan on _hyper_1_2_chunk + Filter: (sensor_id > '-2'::integer) +(6 rows) + :PREFIX SELECT * FROM sample_table WHERE sensor_id < 11; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -230,22 +366,86 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I Filter: (sensor_id < 11) (6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9 and sensor_id < 20; - QUERY PLAN --------------------------------------------------- - Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 9) AND (sensor_id < 20)) -(2 rows) +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 1 AND sensor_id <= 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 1) AND (sensor_id <= 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 1) AND (sensor_id <= 8)) +(6 rows) -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 1 and sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 0 AND sensor_id < 9; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Append -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk - Index Cond: ((sensor_id > 1) AND (sensor_id < 7)) + Index Cond: ((sensor_id > 0) AND (sensor_id < 9)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 0) AND (sensor_id < 9)) +(6 rows) + +-- Query chunk subset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 2 AND sensor_id < 7; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 2) AND (sensor_id < 7)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 2) AND (sensor_id < 7)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 3 AND sensor_id <= 6; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 3) AND (sensor_id <= 6)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 3) AND (sensor_id <= 6)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 4 AND sensor_id <= 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id > 4) AND (sensor_id <= 5)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id > 4) AND (sensor_id <= 5)) +(6 rows) + +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 6 AND sensor_id < 8; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Index Scan using compress_hyper_2_3_chunk_sensor_id__ts_meta_min_1__ts_meta__idx on compress_hyper_2_3_chunk + Index Cond: ((sensor_id >= 6) AND (sensor_id < 8)) + -> Seq Scan on _hyper_1_2_chunk + Filter: ((sensor_id >= 6) AND (sensor_id < 8)) +(6 rows) + +-- Query ranges with OR clause will not work properly due to the way +-- hypertable expansion works as of now. Once we fix that, it should +-- fix the issue here too. +-- Should not include but it does. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1 OR sensor_id > 8; + QUERY PLAN +------------------------------------------------------------ + Append + -> Custom Scan (DecompressChunk) on _hyper_1_1_chunk + -> Seq Scan on compress_hyper_2_3_chunk + Filter: ((sensor_id < 1) OR (sensor_id > 8)) -> Seq Scan on _hyper_1_2_chunk - Filter: ((sensor_id > 1) AND (sensor_id < 7)) + Filter: ((sensor_id < 1) OR (sensor_id > 8)) (6 rows) -- Executor startup time exclusion will also use these ranges appropriately diff --git a/tsl/test/sql/chunk_column_stats.sql.in b/tsl/test/sql/chunk_column_stats.sql.in index 32664c1f8f8..40c6dbd13c8 100644 --- a/tsl/test/sql/chunk_column_stats.sql.in +++ b/tsl/test/sql/chunk_column_stats.sql.in @@ -134,11 +134,44 @@ SELECT * from _timescaledb_catalog.chunk_column_stats WHERE chunk_id = :'CHUNK_I -- A query using a WHERE clause on "sensor_id" column will scan the proper chunk -- due to chunk exclusion using min/max ranges calculated above -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9; +-- First chunk has [start,end) values of [1,9), here we confirm that its being +-- filtered out when we are not hitting that range. + +-- Query ranges outside of chunk stats, should not include first chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1; +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 0; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 8; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 9; :PREFIX SELECT * FROM sample_table WHERE sensor_id = 10; + +-- Query intersecting ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id = 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 2; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 3; +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 1; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 8 AND sensor_id <= 10; +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 4 AND sensor_id > -5; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 6 AND sensor_id < 10; +:PREFIX SELECT * FROM sample_table WHERE sensor_id <= 5 AND sensor_id > -1; + +-- Query chunk superset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > -2; :PREFIX SELECT * FROM sample_table WHERE sensor_id < 11; -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 9 and sensor_id < 20; -:PREFIX SELECT * FROM sample_table WHERE sensor_id > 1 and sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 1 AND sensor_id <= 8; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 0 AND sensor_id < 9; + +-- Query chunk subset ranges, should include chunk. +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 2 AND sensor_id < 7; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 3 AND sensor_id <= 6; +:PREFIX SELECT * FROM sample_table WHERE sensor_id > 4 AND sensor_id <= 5; +:PREFIX SELECT * FROM sample_table WHERE sensor_id >= 6 AND sensor_id < 8; + +-- Query ranges with OR clause will not work properly due to the way +-- hypertable expansion works as of now. Once we fix that, it should +-- fix the issue here too. +-- Should not include but it does. +:PREFIX SELECT * FROM sample_table WHERE sensor_id < 1 OR sensor_id > 8; -- Executor startup time exclusion will also use these ranges appropriately :PREFIX UPDATE sample_table set sensor_id = 10 WHERE sensor_id > length(substring(version(),1,9));