mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 10:33:27 +08:00
Handle Sort nodes in ConstraintAwareAppend
When a MergeAppendPath has children that do not produce sorted output a Sort node will be injected during plan creation, those plans would trigger an error about invalid child nodes in ConstraintAwareAppend. This PR makes ConstraintAwareAppend handle those plans correctly.
This commit is contained in:
parent
d1700711cf
commit
a19be04d7b
@ -21,6 +21,8 @@ accidentally triggering the load of a previous DB version.**
|
||||
* #1687 Fix issue with disabling compression when foreign keys are present
|
||||
* #1715 Fix issue with overly aggressive chunk exclusion in outer joins
|
||||
* #1727 Fix compressing INTERVAL columns
|
||||
* #1728 Handle Sort nodes in ConstraintAwareAppend
|
||||
* #1730 Fix partial index handling on chunks
|
||||
|
||||
**Licensing changes**
|
||||
* Reorder and policies around reorder and drop chunks are now
|
||||
@ -31,6 +33,9 @@ accidentally triggering the load of a previous DB version.**
|
||||
* @RJPhillips01 for reporting an issue with drop chunks.
|
||||
* @b4eEx for reporting an issue with disabling compression.
|
||||
* @dark048 for reporting an issue with order by on compressed hypertables
|
||||
* @mrechte for reporting an issue with compressing INTERVAL columns
|
||||
* @tstaehli for reporting an issue with ConstraintAwareAppend
|
||||
* @chadshowalter for reporting an issue with partial index on hypertables
|
||||
|
||||
## 1.6.0 (2020-01-14)
|
||||
|
||||
|
@ -54,18 +54,19 @@ static Plan *
|
||||
get_plans_for_exclusion(Plan *plan)
|
||||
{
|
||||
/* Optimization: If we want to be able to prune */
|
||||
/* when the node is a T_Result, then we need to peek */
|
||||
/* when the node is a T_Result or T_Sort, then we need to peek */
|
||||
/* into the subplans of this Result node. */
|
||||
if (IsA(plan, Result))
|
||||
{
|
||||
Result *res = (Result *) plan;
|
||||
|
||||
if (res->plan.lefttree != NULL && res->plan.righttree == NULL)
|
||||
return res->plan.lefttree;
|
||||
if (res->plan.righttree != NULL && res->plan.lefttree == NULL)
|
||||
return res->plan.righttree;
|
||||
switch (nodeTag(plan))
|
||||
{
|
||||
case T_Result:
|
||||
case T_Sort:
|
||||
Assert(plan->lefttree != NULL && plan->righttree == NULL);
|
||||
return plan->lefttree;
|
||||
|
||||
default:
|
||||
return plan;
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -228,7 +229,7 @@ ca_append_begin(CustomScanState *node, EState *estate, int eflags)
|
||||
if (can_exclude_chunk(&root, estate, scanrelid, restrictinfos))
|
||||
continue;
|
||||
|
||||
*appendplans = lappend(*appendplans, plan);
|
||||
*appendplans = lappend(*appendplans, lfirst(lc_plan));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -53,3 +53,116 @@ select * from test_chartab order by mac_id , ts limit 2;
|
||||
8864 | 0014070000011039 | 150 | Sat Dec 14 02:52:05.863 2019
|
||||
(2 rows)
|
||||
|
||||
-- test constraintawareappend sort node handling
|
||||
SET enable_hashagg TO false;
|
||||
CREATE TABLE public.merge_sort (time timestamp NOT NULL, measure_id integer NOT NULL, device_id integer NOT NULL, value float);
|
||||
SELECT create_hypertable('merge_sort', 'time');
|
||||
create_hypertable
|
||||
-------------------------
|
||||
(3,public,merge_sort,t)
|
||||
(1 row)
|
||||
|
||||
ALTER TABLE merge_sort SET (timescaledb.compress = true, timescaledb.compress_orderby = 'time', timescaledb.compress_segmentby = 'device_id, measure_id');
|
||||
NOTICE: adding index _compressed_hypertable_4_measure_id__ts_meta_sequence_num_idx ON _timescaledb_internal._compressed_hypertable_4 USING BTREE(measure_id, _ts_meta_sequence_num)
|
||||
NOTICE: adding index _compressed_hypertable_4_device_id__ts_meta_sequence_num_idx ON _timescaledb_internal._compressed_hypertable_4 USING BTREE(device_id, _ts_meta_sequence_num)
|
||||
INSERT INTO merge_sort SELECT time, 1, 1, extract(epoch from time) * 0.001 FROM generate_series('2000-01-01'::timestamp,'2000-02-01'::timestamp,'1h'::interval) g1(time);
|
||||
ANALYZE merge_sort;
|
||||
--compress first chunk
|
||||
SELECT
|
||||
compress_chunk(c.schema_name || '.' || c.table_name)
|
||||
FROM _timescaledb_catalog.chunk c
|
||||
INNER JOIN _timescaledb_catalog.hypertable ht ON c.hypertable_id=ht.id
|
||||
WHERE ht.table_name = 'merge_sort'
|
||||
ORDER BY c.id LIMIT 1;
|
||||
compress_chunk
|
||||
----------------------------------------
|
||||
_timescaledb_internal._hyper_3_5_chunk
|
||||
(1 row)
|
||||
|
||||
-- this should have a MergeAppend with children wrapped in Sort nodes
|
||||
EXPLAIN (analyze,costs off,timing off,summary off) SELECT
|
||||
last(time, time) as time,
|
||||
device_id,
|
||||
measure_id,
|
||||
last(value, time) AS value
|
||||
FROM merge_sort
|
||||
WHERE time < now()
|
||||
GROUP BY 2, 3;
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
GroupAggregate (actual rows=1 loops=1)
|
||||
Group Key: merge_sort.device_id, merge_sort.measure_id
|
||||
-> Custom Scan (ConstraintAwareAppend) (actual rows=745 loops=1)
|
||||
Hypertable: merge_sort
|
||||
Chunks left after exclusion: 5
|
||||
-> Merge Append (actual rows=745 loops=1)
|
||||
Sort Key: _hyper_3_5_chunk.device_id, _hyper_3_5_chunk.measure_id
|
||||
-> Custom Scan (DecompressChunk) on _hyper_3_5_chunk (actual rows=120 loops=1)
|
||||
Filter: ("time" < now())
|
||||
-> Sort (actual rows=1 loops=1)
|
||||
Sort Key: compress_hyper_4_10_chunk.device_id, compress_hyper_4_10_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on compress_hyper_4_10_chunk (actual rows=1 loops=1)
|
||||
-> Sort (actual rows=168 loops=1)
|
||||
Sort Key: _hyper_3_6_chunk.device_id, _hyper_3_6_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_6_chunk (actual rows=168 loops=1)
|
||||
Filter: ("time" < now())
|
||||
-> Sort (actual rows=168 loops=1)
|
||||
Sort Key: _hyper_3_7_chunk.device_id, _hyper_3_7_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_7_chunk (actual rows=168 loops=1)
|
||||
Filter: ("time" < now())
|
||||
-> Sort (actual rows=168 loops=1)
|
||||
Sort Key: _hyper_3_8_chunk.device_id, _hyper_3_8_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_8_chunk (actual rows=168 loops=1)
|
||||
Filter: ("time" < now())
|
||||
-> Sort (actual rows=121 loops=1)
|
||||
Sort Key: _hyper_3_9_chunk.device_id, _hyper_3_9_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_9_chunk (actual rows=121 loops=1)
|
||||
Filter: ("time" < now())
|
||||
(33 rows)
|
||||
|
||||
-- this should exclude the decompressed chunk
|
||||
EXPLAIN (analyze,costs off,timing off,summary off) SELECT
|
||||
last(time, time) as time,
|
||||
device_id,
|
||||
measure_id,
|
||||
last(value, time) AS value
|
||||
FROM merge_sort
|
||||
WHERE time > '2000-01-10'::text::timestamp
|
||||
GROUP BY 2, 3;
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------------------------------------------------------------------------
|
||||
GroupAggregate (actual rows=1 loops=1)
|
||||
Group Key: merge_sort.device_id, merge_sort.measure_id
|
||||
-> Custom Scan (ConstraintAwareAppend) (actual rows=528 loops=1)
|
||||
Hypertable: merge_sort
|
||||
Chunks left after exclusion: 4
|
||||
-> Merge Append (actual rows=528 loops=1)
|
||||
Sort Key: _hyper_3_6_chunk.device_id, _hyper_3_6_chunk.measure_id
|
||||
-> Sort (actual rows=71 loops=1)
|
||||
Sort Key: _hyper_3_6_chunk.device_id, _hyper_3_6_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Index Scan using _hyper_3_6_chunk_merge_sort_time_idx on _hyper_3_6_chunk (actual rows=71 loops=1)
|
||||
Index Cond: ("time" > ('2000-01-10'::cstring)::timestamp without time zone)
|
||||
-> Sort (actual rows=168 loops=1)
|
||||
Sort Key: _hyper_3_7_chunk.device_id, _hyper_3_7_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_7_chunk (actual rows=168 loops=1)
|
||||
Filter: ("time" > ('2000-01-10'::cstring)::timestamp without time zone)
|
||||
-> Sort (actual rows=168 loops=1)
|
||||
Sort Key: _hyper_3_8_chunk.device_id, _hyper_3_8_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_8_chunk (actual rows=168 loops=1)
|
||||
Filter: ("time" > ('2000-01-10'::cstring)::timestamp without time zone)
|
||||
-> Sort (actual rows=121 loops=1)
|
||||
Sort Key: _hyper_3_9_chunk.device_id, _hyper_3_9_chunk.measure_id
|
||||
Sort Method: quicksort
|
||||
-> Seq Scan on _hyper_3_9_chunk (actual rows=121 loops=1)
|
||||
Filter: ("time" > ('2000-01-10'::cstring)::timestamp without time zone)
|
||||
(27 rows)
|
||||
|
||||
RESET enable_hashagg;
|
||||
|
@ -26,4 +26,44 @@ select * from test_chartab order by mac_id , ts limit 2;
|
||||
SELECT compress_chunk('_timescaledb_internal._hyper_1_2_chunk');
|
||||
select * from test_chartab order by mac_id , ts limit 2;
|
||||
|
||||
-- test constraintawareappend sort node handling
|
||||
SET enable_hashagg TO false;
|
||||
|
||||
CREATE TABLE public.merge_sort (time timestamp NOT NULL, measure_id integer NOT NULL, device_id integer NOT NULL, value float);
|
||||
SELECT create_hypertable('merge_sort', 'time');
|
||||
ALTER TABLE merge_sort SET (timescaledb.compress = true, timescaledb.compress_orderby = 'time', timescaledb.compress_segmentby = 'device_id, measure_id');
|
||||
|
||||
INSERT INTO merge_sort SELECT time, 1, 1, extract(epoch from time) * 0.001 FROM generate_series('2000-01-01'::timestamp,'2000-02-01'::timestamp,'1h'::interval) g1(time);
|
||||
|
||||
ANALYZE merge_sort;
|
||||
|
||||
--compress first chunk
|
||||
SELECT
|
||||
compress_chunk(c.schema_name || '.' || c.table_name)
|
||||
FROM _timescaledb_catalog.chunk c
|
||||
INNER JOIN _timescaledb_catalog.hypertable ht ON c.hypertable_id=ht.id
|
||||
WHERE ht.table_name = 'merge_sort'
|
||||
ORDER BY c.id LIMIT 1;
|
||||
|
||||
-- this should have a MergeAppend with children wrapped in Sort nodes
|
||||
EXPLAIN (analyze,costs off,timing off,summary off) SELECT
|
||||
last(time, time) as time,
|
||||
device_id,
|
||||
measure_id,
|
||||
last(value, time) AS value
|
||||
FROM merge_sort
|
||||
WHERE time < now()
|
||||
GROUP BY 2, 3;
|
||||
|
||||
-- this should exclude the decompressed chunk
|
||||
EXPLAIN (analyze,costs off,timing off,summary off) SELECT
|
||||
last(time, time) as time,
|
||||
device_id,
|
||||
measure_id,
|
||||
last(value, time) AS value
|
||||
FROM merge_sort
|
||||
WHERE time > '2000-01-10'::text::timestamp
|
||||
GROUP BY 2, 3;
|
||||
|
||||
RESET enable_hashagg;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user