timescaledb/tsl/test/expected/recompress_chunk_segmentwise.out
Konstantina Skovola 72c0f5b25e Rewrite recompress_chunk in C for segmentwise processing
This patch introduces a C-function to perform the recompression at
a finer granularity instead of decompressing and subsequently
compressing the entire chunk.

This improves performance for the following reasons:
- it needs to sort less data at a time and
- it avoids recreating the decompressed chunk and the heap
inserts associated with that by decompressing each segment
into a tuplesort instead.

If no segmentby is specified when enabling compression or if an
index does not exist on the compressed chunk then the operation is
performed as before, decompressing and subsequently
compressing the entire chunk.
2023-03-23 11:39:43 +02:00

506 lines
34 KiB
Plaintext

-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
\c :TEST_DBNAME :ROLE_SUPERUSER
CREATE OR REPLACE VIEW compressed_chunk_info_view AS
SELECT
h.schema_name AS hypertable_schema,
h.table_name AS hypertable_name,
c.schema_name as chunk_schema,
c.table_name as chunk_name,
c.status as chunk_status,
comp.schema_name as compressed_chunk_schema,
comp.table_name as compressed_chunk_name,
c.id as chunk_id
FROM
_timescaledb_catalog.hypertable h JOIN
_timescaledb_catalog.chunk c ON h.id = c.hypertable_id
LEFT JOIN _timescaledb_catalog.chunk comp
ON comp.id = c.compressed_chunk_id
;
CREATE OR REPLACE VIEW compression_rowcnt_view AS
select ccs.numrows_pre_compression, ccs.numrows_post_compression,
(v.chunk_schema || '.' || v.chunk_name) as chunk_name,
v.chunk_id as chunk_id
from _timescaledb_catalog.compression_chunk_size ccs
join compressed_chunk_info_view v on ccs.chunk_id = v.chunk_id;
------------- only one segment exists and only one segment affected ---------
create table mytab_oneseg (time timestamptz not null, a int, b int, c int);
SELECT create_hypertable('mytab_oneseg', 'time', chunk_time_interval => interval '1 day');
create_hypertable
---------------------------
(1,public,mytab_oneseg,t)
(1 row)
insert into mytab_oneseg values
('2023-01-01 21:56:20.048355+02'::timestamptz, 2, NULL, 2),
('2023-01-01 21:56:10.048355+02'::timestamptz, 2, NULL, 2); --same chunk same segment
alter table mytab_oneseg set (timescaledb.compress, timescaledb.compress_segmentby = 'a, c');
select show_chunks as chunk_to_compress_1 from show_chunks('mytab_oneseg') limit 1 \gset
select compress_chunk(:'chunk_to_compress_1');
compress_chunk
----------------------------------------
_timescaledb_internal._hyper_1_1_chunk
(1 row)
SELECT compressed_chunk_schema || '.' || compressed_chunk_name as compressed_chunk_name_1
from compressed_chunk_info_view where hypertable_name = 'mytab_oneseg' \gset
SELECT ctid, * FROM :compressed_chunk_name_1;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
-------+----------------------------------------------------------------------+---+---+---+----------------+-----------------------+-------------------------------------+-------------------------------------
(0,1) | BAAAApQ3/qlnY///////Z2mAAAAAAgAAAAIAAAAAAAAA7gAFKG/+g/vGAAUob/+1KMU= | 2 | | 2 | 2 | 10 | Sun Jan 01 11:56:10.048355 2023 PST | Sun Jan 01 11:56:20.048355 2023 PST
(1 row)
-- after compressing the chunk
select numrows_pre_compression, numrows_post_compression from _timescaledb_catalog.compression_chunk_size;
numrows_pre_compression | numrows_post_compression
-------------------------+--------------------------
2 | 1
(1 row)
insert into mytab_oneseg values ('2023-01-01 19:56:20.048355+02'::timestamptz, 2, NULL, 2);
-- after inserting new row in compressed chunk
select numrows_pre_compression, numrows_post_compression from _timescaledb_catalog.compression_chunk_size;
numrows_pre_compression | numrows_post_compression
-------------------------+--------------------------
2 | 1
(1 row)
select _timescaledb_internal.recompress_chunk_segmentwise(:'chunk_to_compress_1');
recompress_chunk_segmentwise
----------------------------------------
_timescaledb_internal._hyper_1_1_chunk
(1 row)
-- check the ctid of the rows in the recompressed chunk to verify that we've written new data
SELECT ctid, * FROM :compressed_chunk_name_1;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
-------+----------------------------------------------------------------------------------+---+---+---+----------------+-----------------------+-------------------------------------+-------------------------------------
(0,2) | BAAAApQ2Uhq14/////5TcU6AAAAAAwAAAAMAAAAAAAAO7gAFKG/+g/vGAAUob/+1KMUAAAADV+w1/w== | 2 | | 2 | 3 | 10 | Sun Jan 01 09:56:20.048355 2023 PST | Sun Jan 01 11:56:20.048355 2023 PST
(1 row)
-- after recompressing chunk
select numrows_pre_compression, numrows_post_compression from _timescaledb_catalog.compression_chunk_size;
numrows_pre_compression | numrows_post_compression
-------------------------+--------------------------
3 | 1
(1 row)
---------------- test1: one affected segment, one unaffected --------------
-- unaffected segment will still be recompressed in a future PR we want to avoid doing this
create table mytab_twoseg (time timestamptz not null, a int, b int, c int);
SELECT create_hypertable('mytab_twoseg', 'time', chunk_time_interval => interval '1 day');
create_hypertable
---------------------------
(3,public,mytab_twoseg,t)
(1 row)
insert into mytab_twoseg values
('2023-01-01 21:56:20.048355+02'::timestamptz, 2, NULL, 2),
('2023-01-01 21:56:20.048355+02'::timestamptz, 3, NULL, 3), --same chunk diff segment
('2023-01-01 21:57:20.048355+02'::timestamptz, 3, NULL, 3);
alter table mytab_twoseg set (timescaledb.compress, timescaledb.compress_segmentby = 'a, c');
select show_chunks as chunk_to_compress_2 from show_chunks('mytab_twoseg') limit 1 \gset
select compress_chunk(:'chunk_to_compress_2');
compress_chunk
----------------------------------------
_timescaledb_internal._hyper_3_3_chunk
(1 row)
-- should have 2 compressed rows
-- select numrows_pre_compression, numrows_post_compression from _timescaledb_catalog.compression_chunk_size ccs
-- join compressed_chunk_info_view v on ccs.chunk_id = v.chunk_id where v.compressed_chunk_schema || '.' || v.compressed_chunk_name
-- = :'chunk_to_compress_2';
select * from compression_rowcnt_view where chunk_name = :'chunk_to_compress_2';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
3 | 2 | _timescaledb_internal._hyper_3_3_chunk | 3
(1 row)
insert into mytab_twoseg values ('2023-01-01 19:56:20.048355+02'::timestamptz, 2, NULL, 2);
select * from :chunk_to_compress_2;
time | a | b | c
-------------------------------------+---+---+---
Sun Jan 01 11:56:20.048355 2023 PST | 2 | | 2
Sun Jan 01 11:57:20.048355 2023 PST | 3 | | 3
Sun Jan 01 11:56:20.048355 2023 PST | 3 | | 3
Sun Jan 01 09:56:20.048355 2023 PST | 2 | | 2
(4 rows)
SELECT compressed_chunk_schema || '.' || compressed_chunk_name as compressed_chunk_name_2
from compressed_chunk_info_view where hypertable_name = 'mytab_twoseg' \gset
select ctid, * from :compressed_chunk_name_2;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
-------+----------------------------------------------------------------------+---+---+---+----------------+-----------------------+-------------------------------------+-------------------------------------
(0,1) | BAAAApQ3/0H94wAClDf/Qf3jAAAAAQAAAAEAAAAAAAAADgAFKG/+g/vG | 2 | | 2 | 1 | 10 | Sun Jan 01 11:56:20.048355 2023 PST | Sun Jan 01 11:56:20.048355 2023 PST
(0,2) | BAAAApQ3/0H94//////8bHkAAAAAAgAAAAIAAAAAAAAA7gAFKHAFqwnGAAUocAzSF8U= | 3 | | 3 | 2 | 10 | Sun Jan 01 11:56:20.048355 2023 PST | Sun Jan 01 11:57:20.048355 2023 PST
(2 rows)
select _timescaledb_internal.recompress_chunk_segmentwise(:'chunk_to_compress_2');
recompress_chunk_segmentwise
----------------------------------------
_timescaledb_internal._hyper_3_3_chunk
(1 row)
-- verify that metadata count looks good
select ctid, * from :compressed_chunk_name_2;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
-------+----------------------------------------------------------------------+---+---+---+----------------+-----------------------+-------------------------------------+-------------------------------------
(0,3) | BAAAApQ2Uhq14/////5S2LgAAAAAAgAAAAIAAAAAAAAA7gAFKG/+g/vGAAUoc1jSi8U= | 2 | | 2 | 2 | 10 | Sun Jan 01 09:56:20.048355 2023 PST | Sun Jan 01 11:56:20.048355 2023 PST
(0,4) | BAAAApQ3/0H94//////8bHkAAAAAAgAAAAIAAAAAAAAA7gAFKHAFqwnGAAUocAzSF8U= | 3 | | 3 | 2 | 10 | Sun Jan 01 11:56:20.048355 2023 PST | Sun Jan 01 11:57:20.048355 2023 PST
(2 rows)
-- verify that initial data is returned as expected
select * from :chunk_to_compress_2;
time | a | b | c
-------------------------------------+---+---+---
Sun Jan 01 11:56:20.048355 2023 PST | 2 | | 2
Sun Jan 01 09:56:20.048355 2023 PST | 2 | | 2
Sun Jan 01 11:57:20.048355 2023 PST | 3 | | 3
Sun Jan 01 11:56:20.048355 2023 PST | 3 | | 3
(4 rows)
-- should still have 2 compressed rows
select * from compression_rowcnt_view where chunk_name = :'chunk_to_compress_2';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
4 | 2 | _timescaledb_internal._hyper_3_3_chunk | 3
(1 row)
----------------- more than one batch per segment ----------------------
-- test that metadata sequence number is correct
create table mytab2(time timestamptz not null, a int, b int, c int);
select create_hypertable('mytab2', 'time', chunk_time_interval => interval '1 week');
create_hypertable
---------------------
(5,public,mytab2,t)
(1 row)
insert into mytab2 (time, a, c) select t,s,s from
generate_series('2023-01-01 00:00:00+00'::timestamptz, '2023-01-01 00:00:00+00'::timestamptz + interval '1 day', interval '30 sec') t cross join generate_series(0,2, 1) s;
alter table mytab2 set (timescaledb.compress, timescaledb.compress_segmentby = 'a, c');
select compress_chunk(c) from show_chunks('mytab2') c;
compress_chunk
----------------------------------------
_timescaledb_internal._hyper_5_5_chunk
(1 row)
SELECT compressed_chunk_schema || '.' || compressed_chunk_name as compressed_chunk_name_2
from compressed_chunk_info_view where hypertable_name = 'mytab2'
and compressed_chunk_name is not null limit 1 \gset
insert into mytab2 values ('2023-01-01 00:00:02+00'::timestamptz, 0, NULL, 0); -- goes into the uncompressed chunk
select show_chunks('mytab2') as chunk_to_compress_2 \gset
select ctid, * from :compressed_chunk_name_2;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
-------+----------------------------------------------------------------------------------+---+---+---+----------------+-----------------------+------------------------------+------------------------------
(0,1) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 0 | | 0 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,2) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 0 | | 0 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,3) | BAAAApQnSNVgAP/////+NjyAAAADcQAAAAMAAAAAAAAP7gAFKFrcytAAAAUoWuBeVv8AADbwAAAAAA== | 0 | | 0 | 881 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(0,4) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 1 | | 1 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,5) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 1 | | 1 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,6) | BAAAApQnSNVgAP/////+NjyAAAADcQAAAAMAAAAAAAAP7gAFKFrcytAAAAUoWuBeVv8AADbwAAAAAA== | 1 | | 1 | 881 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(0,7) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 2 | | 2 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,8) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 2 | | 2 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,9) | BAAAApQnSNVgAP/////+NjyAAAADcQAAAAMAAAAAAAAP7gAFKFrcytAAAAUoWuBeVv8AADbwAAAAAA== | 2 | | 2 | 881 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(9 rows)
-- after compression
select * from compression_rowcnt_view where chunk_name = :'chunk_to_compress_2';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
8643 | 9 | _timescaledb_internal._hyper_5_5_chunk | 5
(1 row)
select _timescaledb_internal.recompress_chunk_segmentwise(:'chunk_to_compress_2');
recompress_chunk_segmentwise
----------------------------------------
_timescaledb_internal._hyper_5_5_chunk
(1 row)
select ctid, * from :compressed_chunk_name_2;
ctid | time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
--------+------------------------------------------------------------------------------------------+---+---+---+----------------+-----------------------+------------------------------+------------------------------
(0,10) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 0 | | 0 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,11) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 0 | | 0 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,12) | BAAAApQnSNVgAP//////4XuAAAADcgAAAAQAAAAAAADf7gAFKFrcytAAAAUoWuBeVv8AADbgAAAAAAMZdQAAPQkA | 0 | | 0 | 882 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(0,13) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 1 | | 1 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,14) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 1 | | 1 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,15) | BAAAApQnSNVgAP/////+NjyAAAADcQAAAAMAAAAAAAAP7gAFKFrcytAAAAUoWuBeVv8AADbwAAAAAA== | 1 | | 1 | 881 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(0,16) | BAAAApQ0bFLXgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKHbNWYAAAAUodtDtBv8AAD5gAAAAAA== | 2 | | 2 | 1000 | 10 | Sun Jan 01 07:40:30 2023 PST | Sun Jan 01 16:00:00 2023 PST
(0,17) | BAAAApQtcC8rgP/////+NjyAAAAD6AAAAAMAAAAAAAAP7gAFKGjVEigAAAUoaNilrv8AAD5gAAAAAA== | 2 | | 2 | 1000 | 20 | Sat Dec 31 23:20:30 2022 PST | Sun Jan 01 07:40:00 2023 PST
(0,18) | BAAAApQnSNVgAP/////+NjyAAAADcQAAAAMAAAAAAAAP7gAFKFrcytAAAAUoWuBeVv8AADbwAAAAAA== | 2 | | 2 | 881 | 30 | Sat Dec 31 16:00:00 2022 PST | Sat Dec 31 23:20:00 2022 PST
(9 rows)
-- after recompression
select * from compression_rowcnt_view where chunk_name = :'chunk_to_compress_2';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
8644 | 9 | _timescaledb_internal._hyper_5_5_chunk | 5
(1 row)
-- failing test from compression_ddl
CREATE TABLE test_defaults(time timestamptz NOT NULL, device_id int);
SELECT create_hypertable('test_defaults','time');
create_hypertable
----------------------------
(7,public,test_defaults,t)
(1 row)
ALTER TABLE test_defaults SET (timescaledb.compress,timescaledb.compress_segmentby='device_id');
-- create 2 chunks
INSERT INTO test_defaults SELECT '2000-01-01', 1;
INSERT INTO test_defaults SELECT '2001-01-01', 1;
SELECT compress_chunk(show_chunks) AS "compressed_chunk" FROM show_chunks('test_defaults') ORDER BY show_chunks::text LIMIT 1 \gset
select * from compression_rowcnt_view where chunk_name = :'compressed_chunk';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
1 | 1 | _timescaledb_internal._hyper_7_7_chunk | 7
(1 row)
SELECT * FROM test_defaults ORDER BY 1;
time | device_id
------------------------------+-----------
Sat Jan 01 00:00:00 2000 PST | 1
Mon Jan 01 00:00:00 2001 PST | 1
(2 rows)
ALTER TABLE test_defaults ADD COLUMN c1 int;
ALTER TABLE test_defaults ADD COLUMN c2 int NOT NULL DEFAULT 42;
SELECT * FROM test_defaults ORDER BY 1,2;
time | device_id | c1 | c2
------------------------------+-----------+----+----
Sat Jan 01 00:00:00 2000 PST | 1 | | 42
Mon Jan 01 00:00:00 2001 PST | 1 | | 42
(2 rows)
INSERT INTO test_defaults SELECT '2000-01-01', 2;
SELECT * FROM test_defaults ORDER BY 1,2;
time | device_id | c1 | c2
------------------------------+-----------+----+----
Sat Jan 01 00:00:00 2000 PST | 1 | | 42
Sat Jan 01 00:00:00 2000 PST | 2 | | 42
Mon Jan 01 00:00:00 2001 PST | 1 | | 42
(3 rows)
call recompress_chunk(:'compressed_chunk');
SELECT * FROM test_defaults ORDER BY 1,2;
time | device_id | c1 | c2
------------------------------+-----------+----+----
Sat Jan 01 00:00:00 2000 PST | 1 | | 42
Sat Jan 01 00:00:00 2000 PST | 2 | | 42
Mon Jan 01 00:00:00 2001 PST | 1 | | 42
(3 rows)
-- here we will have an additional compressed row after recompression because the new
-- data corresponds to a new segment
select * from compression_rowcnt_view where chunk_name = :'compressed_chunk';
numrows_pre_compression | numrows_post_compression | chunk_name | chunk_id
-------------------------+--------------------------+----------------------------------------+----------
2 | 2 | _timescaledb_internal._hyper_7_7_chunk | 7
(1 row)
-- test prepared statements
-- PREPRE A SELECT before recompress and perform it after recompress
CREATE TABLE mytab_prep (time timestamptz, a int, b int, c int);
SELECT create_hypertable('mytab_prep', 'time');
NOTICE: adding not-null constraint to column "time"
create_hypertable
-------------------------
(9,public,mytab_prep,t)
(1 row)
INSERT INTO mytab_prep VALUES ('2023-01-01'::timestamptz, 2, NULL, 2),
('2023-01-01'::timestamptz, 2, NULL, 2);
alter table mytab_prep set (timescaledb.compress, timescaledb.compress_segmentby = 'a, c');
PREPARE p1 AS
SELECT * FROM mytab_prep;
select show_chunks as chunk_to_compress_prep from show_chunks('mytab_prep') limit 1 \gset
SELECT compress_chunk(:'chunk_to_compress_prep'); -- the output of the prepared plan would change before and after compress
compress_chunk
-----------------------------------------
_timescaledb_internal._hyper_9_10_chunk
(1 row)
INSERT INTO mytab_prep VALUES ('2023-01-01'::timestamptz, 2, 3, 2);
-- plan should be invalidated to return results from the uncompressed chunk also
EXPLAIN (COSTS OFF) EXECUTE p1;
QUERY PLAN
----------------------------------------------------------
Append
-> Custom Scan (DecompressChunk) on _hyper_9_10_chunk
-> Seq Scan on compress_hyper_10_11_chunk
-> Seq Scan on _hyper_9_10_chunk
(4 rows)
EXECUTE p1;
time | a | b | c
------------------------------+---+---+---
Sun Jan 01 00:00:00 2023 PST | 2 | | 2
Sun Jan 01 00:00:00 2023 PST | 2 | | 2
Sun Jan 01 00:00:00 2023 PST | 2 | 3 | 2
(3 rows)
-- check plan again after recompression
CALL recompress_chunk(:'chunk_to_compress_prep');
EXPLAIN (COSTS OFF) EXECUTE p1;
QUERY PLAN
----------------------------------------------------
Custom Scan (DecompressChunk) on _hyper_9_10_chunk
-> Seq Scan on compress_hyper_10_11_chunk
(2 rows)
EXECUTE p1;
time | a | b | c
------------------------------+---+---+---
Sun Jan 01 00:00:00 2023 PST | 2 | | 2
Sun Jan 01 00:00:00 2023 PST | 2 | | 2
Sun Jan 01 00:00:00 2023 PST | 2 | 3 | 2
(3 rows)
-- verify segmentwise recompression when index exists, decompress + compress otherwise
-- we verify by checking the compressed chunk after recompression in both cases.
-- in the first case, it is the same before and after
-- in the second case, a new compressed chunk is created
CREATE TABLE mytab (time timestamptz, a int, b int, c int);
SELECT create_hypertable('mytab', 'time');
NOTICE: adding not-null constraint to column "time"
create_hypertable
---------------------
(11,public,mytab,t)
(1 row)
INSERT INTO mytab VALUES ('2023-01-01'::timestamptz, 2, NULL, 2),
('2023-01-01'::timestamptz, 2, NULL, 2);
select show_chunks as chunk_to_compress_mytab from show_chunks('mytab') limit 1 \gset
-- index exists, recompression should happen segment by segment so expect a debug message
alter table mytab set (timescaledb.compress, timescaledb.compress_segmentby = 'a, c');
select compress_chunk(show_chunks('mytab'));
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_11_12_chunk
(1 row)
select compressed_chunk_name as compressed_chunk_name_before_recompression from compressed_chunk_info_view where hypertable_name = 'mytab' \gset
INSERT INTO mytab VALUES ('2023-01-01'::timestamptz, 2, 3, 2);
-- segmentwise recompression should not create a new compressed chunk, so verify compressed chunk is the same after recompression
call recompress_chunk(:'chunk_to_compress_mytab');
select compressed_chunk_name as compressed_chunk_name_after_recompression from compressed_chunk_info_view where hypertable_name = 'mytab' \gset
select :'compressed_chunk_name_before_recompression' as before_segmentwise_recompression, :'compressed_chunk_name_after_recompression' as after_segmentwise_recompression;
before_segmentwise_recompression | after_segmentwise_recompression
----------------------------------+---------------------------------
compress_hyper_12_13_chunk | compress_hyper_12_13_chunk
(1 row)
SELECT decompress_chunk(show_chunks('mytab'));
decompress_chunk
------------------------------------------
_timescaledb_internal._hyper_11_12_chunk
(1 row)
alter table mytab set (timescaledb.compress = false);
alter table mytab set (timescaledb.compress);
select compress_chunk(show_chunks('mytab'));
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_11_12_chunk
(1 row)
select compressed_chunk_name as compressed_chunk_name_before_recompression from compressed_chunk_info_view where hypertable_name = 'mytab' \gset
INSERT INTO mytab VALUES ('2023-01-01'::timestamptz, 2, 3, 2);
-- expect to see a different compressed chunk after recompressing now as the operation is decompress + compress
call recompress_chunk(:'chunk_to_compress_mytab');
select compressed_chunk_name as compressed_chunk_name_after_recompression from compressed_chunk_info_view where hypertable_name = 'mytab' \gset
select :'compressed_chunk_name_before_recompression' as before_recompression, :'compressed_chunk_name_after_recompression' as after_recompression;
before_recompression | after_recompression
----------------------------+----------------------------
compress_hyper_13_14_chunk | compress_hyper_13_15_chunk
(1 row)
-- check behavior with NULL values in segmentby columns
select '2022-01-01 09:00:00+00' as start_time \gset
create table nullseg_one (time timestamptz, a int, b int);
select create_hypertable('nullseg_one', 'time');
NOTICE: adding not-null constraint to column "time"
create_hypertable
---------------------------
(14,public,nullseg_one,t)
(1 row)
insert into nullseg_one values (:'start_time', 1, 1), (:'start_time', 1, 2), (:'start_time', 2,2), (:'start_time', 2,3);
alter table nullseg_one set (timescaledb.compress, timescaledb.compress_segmentby= 'a');
select compress_chunk(show_chunks('nullseg_one'));
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_14_16_chunk
(1 row)
insert into nullseg_one values (:'start_time', NULL, 4);
select show_chunks as chunk_to_compress from show_chunks('nullseg_one') limit 1 \gset
select compressed_chunk_schema || '.' || compressed_chunk_name as compressed_chunk_name from compressed_chunk_info_view where hypertable_name = 'nullseg_one' \gset
call recompress_chunk(:'chunk_to_compress');
select * from :compressed_chunk_name;
time | a | b | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
----------------------------------------------------------------------+---+----------------------------------------------------------+----------------+-----------------------+------------------------------+------------------------------
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 1 | BAAAAAAAAAAAAgAAAAAAAAABAAAAAgAAAAEAAAAAAAAAAgAAAAAAAAAC | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 2 | BAAAAAAAAAAAAwAAAAAAAAABAAAAAgAAAAEAAAAAAAAAAwAAAAAAAAAM | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | | BAAAAAAAAAAABAAAAAAAAAAEAAAAAQAAAAEAAAAAAAAABAAAAAAAAAAI | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
(3 rows)
-- insert again, check both reindex works and NULL values properly handled
insert into nullseg_one values (:'start_time', NULL, 4);
call recompress_chunk(:'chunk_to_compress');
select * from :compressed_chunk_name;
time | a | b | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
----------------------------------------------------------------------+---+----------------------------------------------------------+----------------+-----------------------+------------------------------+------------------------------
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 1 | BAAAAAAAAAAAAgAAAAAAAAABAAAAAgAAAAEAAAAAAAAAAgAAAAAAAAAC | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 2 | BAAAAAAAAAAAAwAAAAAAAAABAAAAAgAAAAEAAAAAAAAAAwAAAAAAAAAM | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | | BAAAAAAAAAAABAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAABAAAAAAAAAB4 | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
(3 rows)
-- test multiple NULL segmentby columns
create table nullseg_many (time timestamptz, a int, b int, c int);
select create_hypertable('nullseg_many', 'time');
NOTICE: adding not-null constraint to column "time"
create_hypertable
----------------------------
(16,public,nullseg_many,t)
(1 row)
insert into nullseg_many values (:'start_time', 1, 1, 1), (:'start_time', 1, 2, 2), (:'start_time', 2,2, 2), (:'start_time', 2,3, 3), (:'start_time', 2, NULL, 3);
alter table nullseg_many set (timescaledb.compress, timescaledb.compress_segmentby= 'a, c');
select compress_chunk(show_chunks('nullseg_many'));
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_16_18_chunk
(1 row)
-- new segment (1, NULL)
insert into nullseg_many values (:'start_time', 1, 4, NULL);
select show_chunks as chunk_to_compress from show_chunks('nullseg_many') limit 1 \gset
select compressed_chunk_schema || '.' || compressed_chunk_name as compressed_chunk_name from compressed_chunk_info_view where hypertable_name = 'nullseg_many' \gset
call recompress_chunk(:'chunk_to_compress');
select * from :compressed_chunk_name;
time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
----------------------------------------------------------------------+---+------------------------------------------------------------------------------------------+---+----------------+-----------------------+------------------------------+------------------------------
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 1 | BAAAAAAAAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAAAAAAAgAAAAAAAAAC | 1 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 1 | BAAAAAAAAAAAAgAAAAAAAAACAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAE | 2 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 2 | BAAAAAAAAAAAAgAAAAAAAAACAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAE | 2 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 2 | BAEAAAAAAAAAAwAAAAAAAAADAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAGAAAAAgAAAAEAAAAAAAAAAQAAAAAAAAAC | 3 | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 1 | BAAAAAAAAAAABAAAAAAAAAAEAAAAAQAAAAEAAAAAAAAABAAAAAAAAAAI | | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
(5 rows)
-- insert again, check both reindex works and NULL values properly handled
-- should match existing segment (1, NULL)
insert into nullseg_many values (:'start_time', 1, NULL, NULL);
call recompress_chunk(:'chunk_to_compress');
select * from :compressed_chunk_name;
time | a | b | c | _ts_meta_count | _ts_meta_sequence_num | _ts_meta_min_1 | _ts_meta_max_1
----------------------------------------------------------------------+---+------------------------------------------------------------------------------------------+---+----------------+-----------------------+------------------------------+------------------------------
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 1 | BAAAAAAAAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAAAAAAAgAAAAAAAAAC | 1 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 1 | BAAAAAAAAAAAAgAAAAAAAAACAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAE | 2 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 1 | BAEAAAAAAAAABAAAAAAAAAAEAAAAAQAAAAEAAAAAAAAABAAAAAAAAAAIAAAAAgAAAAEAAAAAAAAAAQAAAAAAAAAC | | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAACd4BH8kQAAAAAAQAAAAEAAAAAAAAADgAE7wCP5IgA | 2 | BAAAAAAAAAAAAgAAAAAAAAACAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAE | 2 | 1 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | 2 | BAEAAAAAAAAAAwAAAAAAAAADAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAAGAAAAAgAAAAEAAAAAAAAAAQAAAAAAAAAC | 3 | 2 | 10 | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
(5 rows)