Skip to content

Commit ffd61eb

Browse files
svenklemmtimescale-automation
authored andcommitted
Fix uncompressed size estimate for text segmentby columns
The size estimate built a query that called compressed_data_column_size on every variable length column. Variable length segmentby columns were handled incorrectly and need to use pg_column_size instead of compressed_data_column_size. (cherry picked from commit ddae6bf)
1 parent e71f92e commit ffd61eb

4 files changed

Lines changed: 48 additions & 3 deletions

File tree

.unreleased/pr_10073

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes: #10073 Fix uncompressed size estimate for varlen

sql/size_utils.sql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ AS $$
597597
DECLARE
598598
v_compressed_chunk regclass;
599599
v_uncompressed_chunk regclass;
600+
v_segmentby text[];
600601
v_index regclass;
601602
v_fixed_column_size integer;
602603
v_num_varlen_columns integer;
@@ -612,7 +613,7 @@ BEGIN
612613

613614
v_compressed_chunk := $1;
614615

615-
SELECT relid INTO v_uncompressed_chunk FROM _timescaledb_catalog.compression_settings WHERE compress_relid = v_compressed_chunk;
616+
SELECT relid, segmentby INTO v_uncompressed_chunk, v_segmentby FROM _timescaledb_catalog.compression_settings WHERE compress_relid = v_compressed_chunk;
616617
IF NOT FOUND THEN
617618
RETURN;
618619
END IF;
@@ -632,7 +633,11 @@ BEGIN
632633
v_tuple_data := v_tuple_data + 7 & ~7; -- align to 8 bytes
633634

634635
IF v_num_varlen_columns > 0 THEN
635-
SELECT ' + (' || string_agg(format('sum(_timescaledb_functions.compressed_data_column_size(%I,NULL::%s))', attname, pg_catalog.format_type(atttypid, atttypmod)), ' + ') || ')' FROM pg_attribute INTO v_varlen_query WHERE attrelid = v_uncompressed_chunk AND attnum > 0 AND NOT attisdropped AND attlen = -1;
636+
SELECT ' + (' || string_agg(
637+
CASE WHEN attname = ANY(v_segmentby)
638+
THEN format('sum(pg_catalog.pg_column_size(%I) * _ts_meta_count)', attname)
639+
ELSE format('sum(_timescaledb_functions.compressed_data_column_size(%I,NULL::%s))', attname, pg_catalog.format_type(atttypid, atttypmod))
640+
END, ' + ') || ')' FROM pg_attribute INTO v_varlen_query WHERE attrelid = v_uncompressed_chunk AND attnum > 0 AND NOT attisdropped AND attlen = -1;
636641
END IF;
637642

638643
EXECUTE format('SELECT sum(_ts_meta_count) FROM %s', v_compressed_chunk) INTO tuples;
@@ -643,7 +648,11 @@ BEGIN
643648
FOR v_index, v_varlen_query, v_columns IN
644649
SELECT
645650
i.indexrelid::regclass,
646-
(SELECT ' + (' || string_agg(format('sum(_timescaledb_functions.compressed_data_column_size(%I,NULL::%s))', attname, pg_catalog.format_type(atttypid, atttypmod)), ' + ' ORDER BY attnum) || ')' FROM pg_attribute att WHERE att.attrelid=i.indrelid AND attnum =ANY(i.indkey)),
651+
(SELECT ' + (' || string_agg(
652+
CASE WHEN attname = ANY(v_segmentby)
653+
THEN format('sum(pg_catalog.pg_column_size(%I) * _ts_meta_count)', attname)
654+
ELSE format('sum(_timescaledb_functions.compressed_data_column_size(%I,NULL::%s))', attname, pg_catalog.format_type(atttypid, atttypmod))
655+
END, ' + ' ORDER BY attnum) || ')' FROM pg_attribute att WHERE att.attrelid=i.indrelid AND attnum =ANY(i.indkey)),
647656
array_length(i.indkey,1) FROM pg_index i
648657
WHERE i.indrelid = v_uncompressed_chunk
649658
LOOP

tsl/test/expected/uncompressed_size.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,24 @@ SELECT * FROM _timescaledb_functions.estimate_uncompressed_size('_timescaledb_in
4646
--------+---------------+------------+------------
4747
3000 | 138000 | 60000 | 198000
4848

49+
-- test varlen segmentby column keeps
50+
CREATE TABLE t3 (time timestamptz, device text, value float) WITH (tsdb.hypertable, tsdb.segmentby = 'device');
51+
NOTICE: using column "time" as partitioning column
52+
INSERT INTO t3 SELECT '2025-01-01'::timestamptz + format('%s ms', i)::interval, format('Device %s', i%10), 1 + 1/i FROM generate_series(1, 100000) i;
53+
CREATE INDEX t3_device_idx ON t3 (device);
54+
VACUUM FULL t3;
55+
SELECT compress_chunk(chunk) FROM show_chunks('t3') AS chunk;
56+
compress_chunk
57+
----------------------------------------
58+
_timescaledb_internal._hyper_5_7_chunk
59+
60+
SELECT l.relation_size > 0 AS relation_positive,
61+
l.index_size > 0 AS index_positive,
62+
l.total_size = l.relation_size + l.index_size AS total_consistent
63+
FROM show_chunks('t3') AS chunk
64+
JOIN _timescaledb_catalog.compression_settings cs ON cs.relid = chunk
65+
JOIN LATERAL _timescaledb_functions.estimate_uncompressed_size(cs.compress_relid) l ON true;
66+
relation_positive | index_positive | total_consistent
67+
-------------------+----------------+------------------
68+
t | t | t
69+

tsl/test/sql/uncompressed_size.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,17 @@ INSERT INTO t1 SELECT '2026-01-01'::timestamptz + format('%s ms', i)::interval,
2222
SELECT compress_chunk(chunk) FROM show_chunks('t1') AS chunk;
2323
SELECT _timescaledb_functions.compressed_data_info(time), _timescaledb_functions.compressed_data_info(device), _timescaledb_functions.compressed_data_info(value) FROM _timescaledb_internal.compress_hyper_2_6_chunk;
2424
SELECT * FROM _timescaledb_functions.estimate_uncompressed_size('_timescaledb_internal.compress_hyper_2_6_chunk');
25+
26+
-- test varlen segmentby column keeps
27+
CREATE TABLE t3 (time timestamptz, device text, value float) WITH (tsdb.hypertable, tsdb.segmentby = 'device');
28+
INSERT INTO t3 SELECT '2025-01-01'::timestamptz + format('%s ms', i)::interval, format('Device %s', i%10), 1 + 1/i FROM generate_series(1, 100000) i;
29+
CREATE INDEX t3_device_idx ON t3 (device);
30+
VACUUM FULL t3;
31+
SELECT compress_chunk(chunk) FROM show_chunks('t3') AS chunk;
32+
33+
SELECT l.relation_size > 0 AS relation_positive,
34+
l.index_size > 0 AS index_positive,
35+
l.total_size = l.relation_size + l.index_size AS total_consistent
36+
FROM show_chunks('t3') AS chunk
37+
JOIN _timescaledb_catalog.compression_settings cs ON cs.relid = chunk
38+
JOIN LATERAL _timescaledb_functions.estimate_uncompressed_size(cs.compress_relid) l ON true;

0 commit comments

Comments
 (0)