Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parameterization in DecompressChunk path generation #5583

Merged
merged 1 commit into from Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -24,6 +24,7 @@ accidentally triggering the load of a previous DB version.**
* #5442 Decompression may have lost DEFAULT values
* #5459 Fix issue creating dimensional constraints
* #5570 Improve interpolate error message on datatype mismatch
* #5583 Fix parameterization in DecompressChunk path generation

**Thanks**
* @kovetskiy and @DZDomi for reporting peformance regression in Realtime Continuous Aggregates
Expand Down
89 changes: 71 additions & 18 deletions tsl/src/nodes/decompress_chunk/decompress_chunk.c
Expand Up @@ -22,6 +22,7 @@
#include <planner.h>

#include "compat/compat.h"
#include "debug_assert.h"
#include "ts_catalog/hypertable_compression.h"
#include "import/planner.h"
#include "compression/create.h"
Expand Down Expand Up @@ -385,10 +386,8 @@

Assert(chunk->fd.compressed_chunk_id > 0);

Path *uncompressed_path = chunk_rel->pathlist ? (Path *) linitial(chunk_rel->pathlist) : NULL;
Path *uncompressed_partial_path =
chunk_rel->partial_pathlist ? (Path *) linitial(chunk_rel->partial_pathlist) : NULL;
Assert(uncompressed_path);
List *initial_pathlist = chunk_rel->pathlist;
List *initial_partial_pathlist = chunk_rel->partial_pathlist;
chunk_rel->pathlist = NIL;
chunk_rel->partial_pathlist = NIL;

Expand Down Expand Up @@ -554,20 +553,41 @@
* from compressed and uncompressed chunk.
*/
if (ts_chunk_is_partial(chunk))
{
Bitmapset *req_outer = PATH_REQ_OUTER(path);
Path *uncompressed_path =
get_cheapest_path_for_pathkeys(initial_pathlist, NIL, req_outer, TOTAL_COST, false);

/*
* All children of an append path are required to have the same parameterization
* so we reparameterize here when we couldn't get a path with the parameterization
* we need. Reparameterization should always succeed here since uncompressed_path
* should always be a scan.
*/
if (!bms_equal(req_outer, PATH_REQ_OUTER(uncompressed_path)))
{
uncompressed_path = reparameterize_path(root, uncompressed_path, req_outer, 1.0);
if (!uncompressed_path)
continue;
}

Check warning on line 572 in tsl/src/nodes/decompress_chunk/decompress_chunk.c

View check run for this annotation

Codecov / codecov/patch

tsl/src/nodes/decompress_chunk/decompress_chunk.c#L569-L572

Added lines #L569 - L572 were not covered by tests

path = (Path *) create_append_path_compat(root,
chunk_rel,
list_make2(path, uncompressed_path),
NIL /* partial paths */,
NIL /* pathkeys */,
PATH_REQ_OUTER(uncompressed_path),
req_outer,
0,
false,
false,
path->rows + uncompressed_path->rows);
}

/* this has to go after the path is copied for the ordered path since path can get freed in
* add_path */
add_path(chunk_rel, path);
}

/* the chunk_rel now owns the paths, remove them from the compressed_rel so they can't be freed
* if it's planned */
compressed_rel->pathlist = NIL;
Expand All @@ -589,18 +609,51 @@
* from compressed and uncompressed chunk.
*/
path = (Path *) decompress_chunk_path_create(root, info, parallel_workers, child_path);
if (ts_chunk_is_partial(chunk) && uncompressed_partial_path)
path =
(Path *) create_append_path_compat(root,
chunk_rel,
NIL,
list_make2(path, uncompressed_partial_path),
NIL /* pathkeys */,
PATH_REQ_OUTER(uncompressed_partial_path),
parallel_workers,
false,
NIL,
path->rows + uncompressed_path->rows);

if (ts_chunk_is_partial(chunk))
{
Bitmapset *req_outer = PATH_REQ_OUTER(path);
Path *uncompressed_path = NULL;

if (initial_partial_pathlist)
uncompressed_path = get_cheapest_path_for_pathkeys(initial_partial_pathlist,
NIL,
req_outer,
TOTAL_COST,
true);

if (!uncompressed_path)
uncompressed_path = get_cheapest_path_for_pathkeys(initial_pathlist,
NIL,
req_outer,
TOTAL_COST,
true);

/*
* All children of an append path are required to have the same parameterization
* so we reparameterize here when we couldn't get a path with the parameterization
* we need. Reparameterization should always succeed here since uncompressed_path
* should always be a scan.
*/
if (!bms_equal(req_outer, PATH_REQ_OUTER(uncompressed_path)))
{
uncompressed_path =
reparameterize_path(root, uncompressed_path, req_outer, 1.0);
if (!uncompressed_path)
continue;
}

Check warning on line 644 in tsl/src/nodes/decompress_chunk/decompress_chunk.c

View check run for this annotation

Codecov / codecov/patch

tsl/src/nodes/decompress_chunk/decompress_chunk.c#L640-L644

Added lines #L640 - L644 were not covered by tests

path = (Path *) create_append_path_compat(root,
chunk_rel,
NIL,
list_make2(path, uncompressed_path),
NIL /* pathkeys */,
req_outer,
parallel_workers,
false,
NIL,
path->rows + uncompressed_path->rows);
}
add_partial_path(chunk_rel, path);
}
/* the chunk_rel now owns the paths, remove them from the compressed_rel so they can't be
Expand All @@ -611,7 +664,7 @@
compressed_rel->reloptkind = RELOPT_DEADREL;

/* We should never get in the situation with no viable paths. */
Assert(chunk_rel->pathlist != NIL);
Ensure(chunk_rel->pathlist, "could not create decompression path");
}

/*
Expand Down
27 changes: 27 additions & 0 deletions tsl/test/shared/expected/decompress_join-12.out
Expand Up @@ -33,3 +33,30 @@ QUERY PLAN
(13 rows)

DROP TABLE compressed_join_temp;
-- test join with partially compressed chunks
CREATE TABLE partial_join(time timestamptz,device text);
SELECT table_name FROM create_hypertable('partial_join','time');
NOTICE: adding not-null constraint to column "time"
table_name
partial_join
(1 row)

ALTER TABLE partial_join set(timescaledb.compress,timescaledb.compress_segmentby='device');
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT count(*) FROM (SELECT compress_chunk(show_chunks('partial_join'),true)) compress;
count
1
(1 row)

-- make chunk partially compressed
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT * FROM partial_join m1 INNER JOIN partial_join m2 ON m1.device = m2.device;
time | device | time | device
------------------------------+--------+------------------------------+--------
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
(4 rows)

DROP TABLE partial_join;
27 changes: 27 additions & 0 deletions tsl/test/shared/expected/decompress_join-13.out
Expand Up @@ -33,3 +33,30 @@ QUERY PLAN
(13 rows)

DROP TABLE compressed_join_temp;
-- test join with partially compressed chunks
CREATE TABLE partial_join(time timestamptz,device text);
SELECT table_name FROM create_hypertable('partial_join','time');
NOTICE: adding not-null constraint to column "time"
table_name
partial_join
(1 row)

ALTER TABLE partial_join set(timescaledb.compress,timescaledb.compress_segmentby='device');
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT count(*) FROM (SELECT compress_chunk(show_chunks('partial_join'),true)) compress;
count
1
(1 row)

-- make chunk partially compressed
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT * FROM partial_join m1 INNER JOIN partial_join m2 ON m1.device = m2.device;
time | device | time | device
------------------------------+--------+------------------------------+--------
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
(4 rows)

DROP TABLE partial_join;
27 changes: 27 additions & 0 deletions tsl/test/shared/expected/decompress_join-14.out
Expand Up @@ -33,3 +33,30 @@ QUERY PLAN
(13 rows)

DROP TABLE compressed_join_temp;
-- test join with partially compressed chunks
CREATE TABLE partial_join(time timestamptz,device text);
SELECT table_name FROM create_hypertable('partial_join','time');
NOTICE: adding not-null constraint to column "time"
table_name
partial_join
(1 row)

ALTER TABLE partial_join set(timescaledb.compress,timescaledb.compress_segmentby='device');
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT count(*) FROM (SELECT compress_chunk(show_chunks('partial_join'),true)) compress;
count
1
(1 row)

-- make chunk partially compressed
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT * FROM partial_join m1 INNER JOIN partial_join m2 ON m1.device = m2.device;
time | device | time | device
------------------------------+--------+------------------------------+--------
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
(4 rows)

DROP TABLE partial_join;
27 changes: 27 additions & 0 deletions tsl/test/shared/expected/decompress_join-15.out
Expand Up @@ -33,3 +33,30 @@ QUERY PLAN
(13 rows)

DROP TABLE compressed_join_temp;
-- test join with partially compressed chunks
CREATE TABLE partial_join(time timestamptz,device text);
SELECT table_name FROM create_hypertable('partial_join','time');
NOTICE: adding not-null constraint to column "time"
table_name
partial_join
(1 row)

ALTER TABLE partial_join set(timescaledb.compress,timescaledb.compress_segmentby='device');
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT count(*) FROM (SELECT compress_chunk(show_chunks('partial_join'),true)) compress;
count
1
(1 row)

-- make chunk partially compressed
INSERT INTO partial_join SELECT '2000-01-01','d1';
SELECT * FROM partial_join m1 INNER JOIN partial_join m2 ON m1.device = m2.device;
time | device | time | device
------------------------------+--------+------------------------------+--------
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
Sat Jan 01 00:00:00 2000 PST | d1 | Sat Jan 01 00:00:00 2000 PST | d1
(4 rows)

DROP TABLE partial_join;
17 changes: 17 additions & 0 deletions tsl/test/shared/sql/decompress_join.sql.in
Expand Up @@ -18,3 +18,20 @@ LIMIT 1;

DROP TABLE compressed_join_temp;

-- test join with partially compressed chunks
CREATE TABLE partial_join(time timestamptz,device text);

SELECT table_name FROM create_hypertable('partial_join','time');
ALTER TABLE partial_join set(timescaledb.compress,timescaledb.compress_segmentby='device');

INSERT INTO partial_join SELECT '2000-01-01','d1';

SELECT count(*) FROM (SELECT compress_chunk(show_chunks('partial_join'),true)) compress;

-- make chunk partially compressed
INSERT INTO partial_join SELECT '2000-01-01','d1';

SELECT * FROM partial_join m1 INNER JOIN partial_join m2 ON m1.device = m2.device;

DROP TABLE partial_join;